-- Исходная таблица stretch

Для заполнения NULL значений предыдущим не NULL значением в разрезе id и по времени ttime (протяжка вниз) в SQL можно использовать оконные функции с игнорированием NULL.

Короткий ответ

Что ответить на собеседовании

Для заполнения NULL значений предыдущим не NULL значением в разрезе id и по времени ttime (протяжка вниз) в SQL можно использовать оконные функции с игнорированием NULL. В PostgreSQL, например, можно применить функцию LASTVALUE с опцией IGNORE NULLS (если поддерживается), либо использовать MAX с оконным фреймом, или функцию LAG в цикле.

Подробный разбор

Ответ с пояснениями

Условие

-- Исходная таблица 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

Ответ

Для заполнения 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 с соответствующим фреймом.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее