Оконные функции — одна из наиболее мощных возможностей SQL, при этом наименее известная начинающим. Они позволяют выполнять агрегатные вычисления без GROUP BY — сохраняя при этом каждую строку.
Синтаксис OVER()
-- window_syntax.sql
aggregate_function() OVER ( [PARTITION BY column] -- разбивка на группы [ORDER BY column] -- порядок внутри группы [ROWS/RANGE frame] -- окно строк )
ROW_NUMBER, RANK, DENSE_RANK
-- ranking.sql
SELECT employee_name, department, salary, -- Уникальный номер строки ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num, -- Ранг с пропусками при одинаковых значениях RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank, -- Ранг без пропусков DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS d_rank FROM employees;
// Топ-N по группам — классическая задача
Задача: найти 3 самых высокооплачиваемых сотрудника в каждом отделе. Решение: ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) и фильтр WHERE row_num <= 3 в CTE или подзапросе.
LAG и LEAD: доступ к соседним строкам
-- lag_lead.sql
-- Сравнение продаж с предыдущим месяцем SELECT month, revenue, LAG(revenue, 1) OVER (ORDER BY month) AS prev_month, revenue - LAG(revenue, 1) OVER (ORDER BY month) AS change FROM monthly_sales;
SUM OVER: нарастающий итог
-- running_total.sql
SELECT order_date, amount, SUM(amount) OVER ( ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_total FROM orders;