Выберите последнюю строку в группе, дата которой меньше указанной - PullRequest
0 голосов
/ 15 сентября 2018

Это немного сложно, но у меня есть таблица, которая выглядит следующим образом:

Time                  Meter   Value
2018-09-15 11:00:00   IU       0.105
2018-09-15 11:00:00   GD       1.648
2018-09-10 10:00:00   OU      -0.018
2018-09-10 10:00:00   GD       1.659
2018-09-01 19:00:00   OU       0.003
2018-09-01 19:00:00   OD       2.188
2018-09-01 19:00:00   IU       0.096
2018-09-01 19:00:00   GD       1.670

В любое время я хочу получить ближайшее предыдущее значение для каждого отдельного счетчика: например:для времени "2018-09-14 12:00:00" я хочу получить:

2018-09-10 10:00:00 OU  -0.018
2018-09-10 10:00:00 GD  1.659
2018-09-10 04:15:00 KD  0.737
2018-09-01 19:00:00 IU  0.096

Сначала я думал, что этот запрос может работать:

SELECT `meter`, max(`time`) time, `value` 
FROM `data` 
WHERE `time`<= '2018-09-15 12:00:00' 
GROUP BY `meter`;

Он дал ожидаемыйраз, но разные значения.

Затем я подумал, что лучший способ сделать это - использовать этот запрос в качестве основы, а затем выполнить другой запрос, используя вывод:

SELECT `meter`, max(`time`) time 
FROM `data` 
WHERE `time`<= '2018-09-15 12:00:00' 
GROUP BY `meter`;

Вывод:

2018-09-10 10:00:00 OU
2018-09-10 10:00:00 GD
2018-09-10 04:15:00 KD
2018-09-01 19:00:00 IU

Затем в каждой из строк запустите:

SELECT `value` 
FROM `data` 
where `time` = '...' AND `meter` - '...';

Тогда возникает вопрос, как я могу свернуть его в один запрос, чтобы добавить третий столбец, содержащийрезультат второго запроса для каждой строки?

1 Ответ

0 голосов
/ 15 сентября 2018

Я думаю, что самый простой метод - это коррелированный подзапрос:

SELECT d.meter, max(d.time) as time,
       (SELECT d2.value
        FROM data d2
        WHERE d2.meter = d.meter AND
              d2.time <= '2018-09-14 12:00:00'
        ORDER BY d2.time DESC
        LIMIT 1
       ) AS value
FROM data d
WHERE d.time <= '2018-09-14 12:00:00'
GROUP BY d.meter;

Если, конечно, вы не используете MySQL 8.0. В этом случае lag() является лучшим решением:

select d.*, lag(value) over (partition by meter order by time) as prev_value
from data d;
...