SQL оконные функции: ROW_NUMBER, RANK и LAG
Оконная функция SQL вычисляет значение по набору связанных строк, но сохраняет каждую исходную строку в результате. В отличие от GROUP BY, она не сворачивает записи в одну строку на группу. Окно задают через OVER, часто с PARTITION BY и ORDER BY.
Нумерация заказов внутри клиента
CREATE TEMP TABLE orders (customer_id int, order_id int, amount numeric, created_at date);
INSERT INTO orders VALUES
(1, 101, 50, '2026-01-01'),
(1, 102, 75, '2026-01-02'),
(2, 201, 30, '2026-01-01');
SELECT customer_id, order_id,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_at) AS row_num
FROM orders
ORDER BY customer_id, created_at;
-- ожидаемый row_num: 1, 2, 1PARTITION BY начинает нумерацию заново для каждого клиента. ORDER BY внутри окна задаёт порядок расчёта.
Сравнить rank и dense_rank
SELECT amount,
RANK() OVER (ORDER BY amount DESC) AS rank_with_gaps,
DENSE_RANK() OVER (ORDER BY amount DESC) AS rank_without_gaps
FROM (VALUES (100), (100), (80)) AS scores(amount)
ORDER BY amount DESC;При равных значениях RANK() оставляет пропуск в следующем месте, а DENSE_RANK() — нет.
Взять значение из предыдущей строки
WITH orders(customer_id, order_id, amount, created_at) AS (
VALUES (1, 101, 50, DATE '2026-01-01'),
(1, 102, 75, DATE '2026-01-02'),
(2, 201, 30, DATE '2026-01-01')
)
SELECT customer_id, order_id, amount,
LAG(amount) OVER (PARTITION BY customer_id ORDER BY created_at) AS previous_amount
FROM orders;Функция | Результат |
|---|---|
| Уникальный порядковый номер |
| Ранг с пропусками при равных значениях |
| Ранг без пропусков |
| Значение из предыдущей строки окна |
Чем окно отличается от GROUP BY?
GROUP BY агрегирует несколько строк в одну на группу. Оконная функция возвращает рассчитанное значение рядом с каждой строкой.
Как получить сумму с накоплением?
Используйте SUM(amount) OVER (PARTITION BY customer_id ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW).