Оконные функции: анализ без потери строк
Оконные функции, самый мощный инструмент аналитика в SQL. Они считают что-то "по окну" строк, не сворачивая их в одну.
Проблема которую решают оконные функции
Задача: показать каждый заказ вместе с суммарной выручкой клиента.
GROUP BY не подходит, он сворачивает строки, теряем детали по заказам.
Оконная функция, считает агрегат, но сохраняет каждую строку:
SELECT
customer_id,
order_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS customer_total
FROM orders;
customer_id | order_id | amount | customer_total
------------+----------+--------+---------------
1 | 5 | 1200 | 4750 ← сумма всех заказов клиента 1
1 | 8 | 450 | 4750
1 | 15 | 3100 | 4750
2 | 2 | 800 | 3000 ← сумма всех заказов клиента 2
2 | 11 | 2200 | 3000
Синтаксис
функция() OVER (
PARTITION BY столбец -- разбить на группы (необязательно)
ORDER BY столбец -- порядок внутри группы (необязательно)
)
ROW_NUMBER, порядковый номер
-- Пронумеровать заказы каждого клиента по дате
SELECT
customer_id,
order_id,
created_at,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY created_at
) AS order_num
FROM orders;
Классическое применение, найти первый заказ каждого клиента:
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_at) AS rn
FROM orders
)
SELECT * FROM ranked WHERE rn = 1;
LAG и LEAD, предыдущее и следующее
-- Динамика выручки: сколько заработали в этом месяце vs прошлом
SELECT
month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_month,
revenue - LAG(revenue) OVER (ORDER BY month) AS growth
FROM monthly_stats;
Накопительная сумма
SELECT
date,
revenue,
SUM(revenue) OVER (ORDER BY date) AS cumulative_revenue
FROM daily_stats;
💡 Главная мысль: Оконные функции считают агрегаты не теряя строки. PARTITION BY, "по каждой группе". ORDER BY, "в каком порядке". Это открывает целый класс аналитических задач.