SELECT
user_id, order_id, amount,
NTH_VALUE(amount, 2) OVER (
PARTITION BY user_id ORDER BY created_at
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS second_order_amount
FROM orders;
Результат:
user_id | order_id | amount | second_order_amount
--------+----------+--------+--------------------
17 | 1001 | 299 | 1990
17 | 1002 | 1990 | 1990
SELECT
user_id, amount,
NTH_VALUE(amount, 2) OVER (
PARTITION BY user_id ORDER BY created_at
) AS nth_default_frame
FROM orders;
Результат:
user_id | amount | nth_default_frame
--------+--------+------------------
17 | 299 | (null)
17 | 1990 | 1990
SELECT DISTINCT
NTH_VALUE(amount, 3) OVER (
ORDER BY amount DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS third_largest
FROM payments;
Результат:
third_largest
-------------
1990
Порешать SQL-задачи в тренажёре →
Спрашивают в блоке оконных функций рядом с FIRST_VALUE/LAST_VALUE и LAG/LEAD. Любимый trick-вопрос — почему вернулся NULL (правильный ответ: из-за рамки окна по умолчанию).
Почти всегда причина — рамка окна. По умолчанию она заканчивается на текущей строке, поэтому для строк до n-й нужного значения в рамке ещё нет и функция даёт NULL. Добавь ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, чтобы рамка охватывала весь раздел.
Да, в SQLite начиная с версии 3.25 и в MySQL начиная с 8.0 — вместе с остальными оконными функциями. В MySQL 5.7 и более старых оконных функций нет вовсе, поэтому NTH_VALUE там недоступен. PostgreSQL поддерживает её давно.
NTH_VALUE — обобщение: она берёт значение из произвольной n-й строки рамки, тогда как FIRST_VALUE и LAST_VALUE фиксированы на первой и последней. NTH_VALUE(x, 1) эквивалентна FIRST_VALUE(x). Все три одинаково чувствительны к границам рамки окна.
Оконные функции · Ранжирование
ROW_NUMBER · RANK · DENSE_RANK · LAG · LEAD · NTILE
Открыть SQL-тренажёр (565 задач) →