Имитация LAG с GROUP BY в MySQL 5,6 - PullRequest
0 голосов
/ 01 марта 2020

Как мне моделировать функцию LAG с MySQL 8.0 в MySQL 5.6, где я получаю предыдущую информацию с тем же ItemID. Я создал эту иллюстрацию для имитации таблицы и вывода нужного мне запроса. Серые данные - это исходная таблица, а оранжевые - данные из предыдущей строки с тем же ItemID и ближайшей предыдущей датой.

enter image description here

У меня есть попытался присоединиться к таблице самостоятельно с A.ItemID = B.ItemID AND B.Date

Я пробовал это также.

SET @lag = -1;
SELECT *, @lag PreviousInfo, @lag:=Info CurrentInfo FROM Table1

Однако это всегда просто возвращает информацию из предыдущей строки и не группируется по ItemID.

Ответы [ 2 ]

1 голос
/ 01 марта 2020

Вы можете использовать два коррелированных подзапроса:

select
    t.*,
    (
        select date 
        from mytable t1 
        where t1.itemid = t.itemid and t1.date < t.date
        order by t.date desc
        limit 1
    ) previous_date,
    (
        select info 
        from mytable t1 
        where t1.itemid = t.itemid and t1.date < t.date
        order by t.date desc
        limit 1
    ) previous_info
from mytable t

Однако это плохо масштабируется, когда вам нужно восстановить больше столбцов из предыдущей записи. В этом случае мы можем самостоятельно объединиться с условием not exists для фильтрации по предыдущей записи:

select
    t.*,
    tlag.date previous_date,
    tlag.info previous_info
from mytable t
left join mytable tlag
    on  tlag.itemid = t.itemid
    and tlag.date   < t.date
    and not exists (
        select 1
        from mytable t1
        where t1.itemid = t.itemid and t1.date < t.date and t1.date > tlag.date
    )

Для выполнения обоих запросов рассмотрим следующий индекс для (item_id, date). Возможно, вы захотите добавить info к индексу, например: (item_id, date, info), особенно с первым запросом, поэтому оба подзапроса покрыты индексом.

0 голосов
/ 01 марта 2020

Наиболее эффективный способ для большого набора данных - это, вероятно, использование переменных, но вы должны делать это осторожно:

SELECT t1.*,
       (case when (@i <> itemid)
             then (case when (@prevd := date) = null  -- never happens
                        else null
                   end)                 
             when (@stash := @prevd) = null  -- never happens
             then null
             when (@prevd := date) = null    -- never happens
             then null
             else @x
        end) as prev_d                       
FROM (SELECT t1.*
      FROM Table1 t1
      ORDER BY itemid, date
     ) t1 CROSS JOIN
     (SELECT @i := -1, @prevd := null) params;

Использование переменных очень сложно, потому что MySQL не гарантирует порядок вычисления выражений в SELECT. Таким образом, для обеспечения правильного порядка вычисления используется CASE express.

Вам может не потребоваться подзапрос в MySQL 5.6 - ORDER BY во внешнем запросе может обрабатывать переменные ( в какой-то момент около 5.6 / 5.7 это перестало работать).

...