Определение «заправка» немного расплывчато. Я предполагаю, что это заполнение, когда стоимость топлива увеличивается более чем на 50 . Замените на номер по вашему выбору. И похоже, что новый танк должен начинаться с fuel = 100
(хотя это странное условие). Я добавил это в качестве комментария - раскомментируйте для активации:
SELECT *
FROM (
SELECT *, count(*) FILTER (WHERE fillup) OVER (PARTITION BY device_id ORDER BY id) AS tank
FROM (
SELECT *
, fuel - lag(fuel, 1, 0) OVER (PARTITION BY device_id ORDER BY id) > 50
-- AND fuel = 100 -- additional condition(s)?
AS fillup
FROM tbl
) sub1
) sub2
WHERE device_id = 19
AND tank = 1;
db <> fiddle здесь
В подзапросе sub1
, вычислите разницу между предыдущим вводом топлива на устройство и текущим - используя оконную функцию lag()
. Примечательно, что я использую вариант с 3 параметрами, предоставляя 0 по умолчанию для пропущенных строк, чтобы покрыть первую строку на раздел. Увеличение более чем на 50 указывает на новое заполнение.
В подзапросе sub2
подсчитайте количество заполнений с течением времени с помощью другой оконной функции, назначая таким образом номер «резервуара» каждомуrow.
Во внешнем SELECT
выберите свое устройство и номер «заправки» бака. Вуаля.
Если вы переместите условие WHERE device_id = 19
в самый внутренний запрос, вы можете отбросить предложения PARTITION
. Быстрее, менее универсально.
Об условии FILTER
:
Получить только последний резервуар для данного устройства
Согласно вашему комментарию, определенному как "последний раз, когда резервуар был заполнен от 20 или нижедо 100 ".
Я предполагаю, что более поздние моменты времени соответствуют более высоким значениям id
. (Имейте в виду, что при параллельной загрузке записи могут возникнуть сложности в угловых случаях.)
Самый простой способ: просто изменить порядок и отсчитать снизу:
SELECT *
FROM (
SELECT *, count(*) FILTER (WHERE fillup) OVER (ORDER BY id DESC) AS tank
FROM (
SELECT *, lag(fuel, 1, 0) OVER (ORDER BY id DESC) = 100
AND fuel <= 20 AS fillup
FROM tbl
WHERE device_id = 19
) sub1
) sub2
WHERE tank = 0
-- ORDER BY id -- optional to get result in ascending order
db <> fiddle здесь
Для этого, вероятно, быстрее проходить по рядам процедурно, так как для этого требуется только один проход, и он может остановиться сразу послепервый танк найден.
Поддержите его индексом tbl(device_id, id DESC)
.
Пример кода: