Learnly
SQL для аналитиков/Глава 8/Урок 3

Оконные функции: анализ без потери строк

Оконные функции: анализ без потери строк

Оконные функции, самый мощный инструмент аналитика в 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, "в каком порядке". Это открывает целый класс аналитических задач.