SUM() OVER в SQL: оконная сумма, running total и доля

SUM() OVER (...) — это агрегат SUM как оконная функция: он считает сумму по окну, но НЕ схлопывает строки, как обычный GROUP BY. Каждая строка сохраняется и получает рядом нужную сумму. Три главных сценария у аналитика: нарастающий итог (running total), сумма по группе рядом с детальными строками и доля строки в общей сумме.

Синтаксис

SUM(колонка) OVER (PARTITION BY … ORDER BY … ROWS BETWEEN … AND …)

Примеры использования

Пример 1: Нарастающий итог выручки

SELECT day, revenue,
       SUM(revenue) OVER (ORDER BY day
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM daily_sales;

Результат:

day        | revenue | running_total
2026-06-01 | 100     | 100
2026-06-02 | 200     | 300

Пример 2: Доля строки в сумме по клиенту

SELECT user_id, amount,
       ROUND(100.0 * amount / SUM(amount) OVER (PARTITION BY user_id), 1) AS pct_of_user
FROM orders;

Результат:

user_id | amount | pct_of_user
1       | 300    | 75.0
1       | 100    | 25.0
Порешать SQL-задачи в тренажёре →

Типичная ошибка

Ключевое отличие от GROUP BY: SUM() OVER не убирает строки, а «размазывает» сумму по ним. Если добавить ORDER BY внутри OVER, но не задать рамку, по умолчанию берётся сумма от начала до текущей строки (RANGE) — на дубликатах ключа это даёт неожиданный результат, поэтому для running total рамку ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW пишут явно. Без ORDER BY окно считает сумму по всей партиции.

Где спрашивают на собеседовании

SUM() OVER — база задач на running total, долю от целого и «сумму по группе рядом с деталями». На собеседовании часто просят «долю каждого товара в выручке категории» или «накопительную сумму» — и то, и другое это SUM() OVER, а не подзапрос.

FAQ: частые вопросы про SUM OVER

Чем SUM() OVER отличается от SUM() с GROUP BY?

GROUP BY схлопывает строки в одну на группу. SUM() OVER считает ту же сумму, но сохраняет все строки — каждая получает значение окна рядом. Поэтому можно вывести и деталь, и агрегат в одной выборке.

Как сделать нарастающий итог через SUM OVER?

SUM(x) OVER (ORDER BY dt ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW). ORDER BY задаёт порядок накопления, рамка ROWS — что суммируется до текущей строки включительно.

Зачем задавать рамку ROWS явно?

При наличии ORDER BY без явной рамки берётся RANGE до текущей строки, и на одинаковых значениях ключа сумма перепрыгнет через все дубли. Явная рамка ROWS делает поведение предсказуемым.

Задачи в тренажёре по теме

Вопросы с собеседований по теме

Смежные темы SQL

Оконные функции · Агрегации

Другие функции SQL

ROW_NUMBER · RANK · DENSE_RANK · LAG · LEAD · NTILE

Открыть SQL-тренажёр (565 задач) →