-- Исходная таблица stretch -- Необходимо в разрезе id заполнить NULL'ы предыдущим значением (не NULL) - выполнить протяжку вниз id | ttime | val ---|-------|----- 1 | 07:30 | NULL 1 | 09:21 | 10 1 | 13:53 | NULL 1 | 16:12 | NULL 2 | 09:42 | 133 2 | 15:20 | NULL 2 | 21:33 | NULL 3 | 08:01 | NULL 3 | 11:41 | 8 3 | 14:23 | NULL 3 | 16:17 | NULL 3 | 19:54 | 2 4 | 13:10 | 312 4 | 14:42 | NULL 4 | 16:31 | 7 4 | 17:44 | NULL id | ttime | val ---|-------|----- 1 | 07:30 | NULL 1 | 09:21 | 10 1 | 13:53 | 10 1 | 16:12 | 10 2 | 09:42 | 133 2 | 15:20 | 133 2 | 21:33 | 133 3 | 08:01 | NULL 3 | 11:41 | 8 3 | 14:23 | 8 3 | 16:17 | 8 3 | 19:54 | 2 4 | 13:10 | 312 4 | 14:42 | 312 4 | 16:31 | 7 4 | 17:44 | 7 -- Слева исходная таблица, а справа, то что нужно получить SELECT id, ttime, COALESCE(val, LAST_VALUE(val) OVER(PARTITION BY id ORDER BY ttime)) as val FROM stretch
Ответ от нейросети
sobes.tech AI
Для заполнения NULL значений предыдущим не NULL значением в разрезе id и по времени ttime (протяжка вниз) в SQL можно использовать оконные функции с игнорированием NULL. В PostgreSQL, например, можно применить функцию LAST_VALUE с опцией IGNORE NULLS (если поддерживается), либо использовать MAX с оконным фреймом, или функцию LAG в цикле.
Пример решения с использованием MAX и оконной функции:
SELECT
id,
ttime,
-- берем максимум val по всем предыдущим и текущим строкам в рамках id и упорядоченных по времени
MAX(val) OVER (PARTITION BY id ORDER BY ttime ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS val
FROM stretch
ORDER BY id, ttime;
Это работает, потому что MAX игнорирует NULL и всегда берет максимальное значение из предыдущих строк, что соответствует последнему известному значению.
В вашем примере исходного запроса COALESCE(val, LAST_VALUE(val) OVER(...)) не сработает корректно без IGNORE NULLS, так как LAST_VALUE вернет NULL, если текущий val NULL.
Если СУБД поддерживает IGNORE NULLS, можно написать:
SELECT
id,
ttime,
LAST_VALUE(val) IGNORE NULLS OVER (PARTITION BY id ORDER BY ttime ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS val
FROM stretch
ORDER BY id, ttime;
Но в большинстве случаев проще использовать MAX с оконным фреймом.
Таким образом, для протяжки вниз значений NULL предыдущим не NULL значением удобно использовать оконную функцию MAX с соответствующим фреймом.