MySQL Получить изменение от совокупных результатов в последовательных строках по идентификатору - PullRequest
0 голосов
/ 08 апреля 2020

Я использую MySQL Сервер совместной работы версии 8.0.19.

При работе с общедоступными данными COVID19 я боролся со следующей проблемой. Я использую набор данных, который является надежным и хорошего качества, однако данные (total_confirmed) сообщаются с использованием совокупных итогов вместо ежедневных подсчетов инфекций:

+----------------+---------------------+-----------------+
| country_region | date                | total_confirmed |
+----------------+---------------------+-----------------+
| Afghanistan    | 2020-04-05 00:00:00 |             349 |
| Afghanistan    | 2020-04-06 00:00:00 |             367 |
| Afghanistan    | 2020-04-07 00:00:00 |             423 |
| Albania        | 2020-04-05 00:00:00 |             361 |
| Albania        | 2020-04-06 00:00:00 |             377 |
| Albania        | 2020-04-07 00:00:00 |             383 |
| Algeria        | 2020-04-05 00:00:00 |            1320 |
| Algeria        | 2020-04-06 00:00:00 |            1423 |
| Algeria        | 2020-04-07 00:00:00 |            1468 |
+----------------+---------------------+-----------------+

Мои требования иметь как совокупный счет, так и ежедневные новые случаи. Есть отличное решение для этого здесь , и оно работает, как талисман в моем наборе данных, при условии, что я сосредотачиваюсь только на одной стране (я использовал таблицу, заполненную только данными Афганистана в этом примере):

SET @prev := NULL;

SELECT country_region
      ,`date` AS DateCreated
      ,total_confirmed - coalesce(@prev, total_confirmed) AS new_cases
      ,(@prev := total_confirmed) AS total_confirmed
FROM (
        SELECT * FROM so_confirmed ORDER BY `date`
     ) t1
GROUP BY
     country_region, total_confirmed, `date`
ORDER BY country_region, DateCreated;

Вывод:

+----------------+---------------------+-----------+-----------------+
| country_region | DateCreated         | new_cases | total_confirmed |
+----------------+---------------------+-----------+-----------------+
| Afghanistan    | 2020-04-05 00:00:00 |         0 |             349 |
| Afghanistan    | 2020-04-06 00:00:00 |        18 |             367 |
| Afghanistan    | 2020-04-07 00:00:00 |        56 |             423 |
+----------------+---------------------+-----------+-----------------+

Однако, если в данных существует минута, когда существует более одной страны_региона, она полностью терпит неудачу, и я не знаю SQL достаточно хорошо, чтобы выяснить, что мне нужно изменить.

+----------------+---------------------+-----------+-----------------+
| country_region | DateCreated         | new_cases | total_confirmed |
+----------------+---------------------+-----------+-----------------+
| Afghanistan    | 2020-04-05 00:00:00 |         0 |             349 |
| Afghanistan    | 2020-04-06 00:00:00 |      -953 |             367 |
| Afghanistan    | 2020-04-07 00:00:00 |     -1000 |             423 |
| Albania        | 2020-04-05 00:00:00 |        12 |             361 |
| Albania        | 2020-04-06 00:00:00 |        10 |             377 |
| Albania        | 2020-04-07 00:00:00 |       -40 |             383 |
| Algeria        | 2020-04-05 00:00:00 |       959 |            1320 |
| Algeria        | 2020-04-06 00:00:00 |      1046 |            1423 |
| Algeria        | 2020-04-07 00:00:00 |      1085 |            1468 |
+----------------+---------------------+-----------+-----------------+

Желаемый результат:

+----------------+---------------------+-----------+-----------------+
| country_region | DateCreated         | new_cases | total_confirmed |
+----------------+---------------------+-----------+-----------------+
| Afghanistan    | 2020-04-05 00:00:00 |         0 |             349 |
| Afghanistan    | 2020-04-06 00:00:00 |        18 |             367 |
| Afghanistan    | 2020-04-07 00:00:00 |        56 |             423 |
| Albania        | 2020-04-05 00:00:00 |         0 |             361 |
| Albania        | 2020-04-06 00:00:00 |        16 |             377 |
| Albania        | 2020-04-07 00:00:00 |         6 |             383 |
| Algeria        | 2020-04-05 00:00:00 |         0 |            1320 |
| Algeria        | 2020-04-06 00:00:00 |       103 |            1423 |
| Algeria        | 2020-04-07 00:00:00 |        45 |            1468 |
+----------------+---------------------+-----------+-----------------+

Любая помощь будет принята с благодарностью. Очевидно, что в реальном наборе данных значения new_cases не будут равны 0 в 2020-04-05, но в этом примере набор данных будет правильным.

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Вы можете использовать форму с тремя аргументами lag():

select sc.*,
       (total_confirmed -
        lag(total_confirmed, 1, total_confirmed) over (partition by country_region order by date_created)
       ) as new_cases
from so_confirmed sc;

В более старых версиях MySQL вы можете использовать объединение, предполагая, что нет пропущенных дат:

select sc.*,
       coalesce(sc.total_confirmed - sc_prev.total_confirmed, 0) as new_cases
from so_confirmed sc left join
     so_confirmed sc_prev
     on sc_prev.country_region = sc.country_region and
        sc_prev.datecreated = sc.datecreated - interval 1 day;
1 голос
/ 08 апреля 2020

Если вы используете MySQL 8.0, вы можете сделать это с помощью оконной функции lag():

select
    sc.*,
    coalesce(
        total_confirmed - lag(total_confirmed) over(partition by country_region order by datecreated),
        0
    ) new_cases
from so_confirmed sc;
...