← все задачи
SQL · задача 5 из 10
Накопительный итог по дням
Средний
15 минут
SUM OVERрамки окнагруппировка по дате
Условие
Таблица payments (id, paid_at, amount). Посчитайте выручку по дням и нарастающий итог с начала месяца.
Что требуется
- Одна строка на день
- Колонка с суммой за день и колонка с накопленным итогом
- Итог считается в хронологическом порядке
Пример
day revenue running_total 2026-09-01 1000 1000 2026-09-02 500 1500 2026-09-03 700 2200
Сначала уточните
Вопросы до кода — половина оценки. Молча начать печатать хуже, чем задать два вопроса.
- Часовой пояс: сутки по UTC или по местному времени? Граница дня сдвигается
- Нужны ли дни без платежей — их в таблице просто нет
- Накопление с начала месяца или за всё время?
Показать решение Скрыть решение
Решение
SELECT
day,
revenue,
SUM(revenue) OVER (ORDER BY day ROWS UNBOUNDED PRECEDING) AS running_total
FROM (
SELECT
date_trunc('day', paid_at) AS day,
SUM(amount) AS revenue
FROM payments
WHERE paid_at >= date_trunc('month', CURRENT_DATE)
GROUP BY 1
) daily
ORDER BY day;
Почему так
Почему два уровня: сначала группировка, потом окно
- Сначала нужно схлопнуть платежи в дни, и только потом накапливать по дням
- Окно поверх сырых платежей дало бы итог по каждой транзакции, а не по дню
- Порядок «агрегация → окно» — общий шаблон для любых отчётов с накоплением
Зачем ROWS UNBOUNDED PRECEDING
- По умолчанию для окна с ORDER BY рамка — RANGE от начала до текущей строки включая равные ей
- На уникальных днях результат тот же, но при дубликатах ключа RANGE схлопнет их в одно значение
- Явная рамка ROWS убирает неоднозначность — и знание этой детали отличает уверенное владение окнами
Почему WHERE, а не фильтр в окне
- Условие по дате в WHERE отсекает лишние строки до всей работы — это самый дешёвый фильтр
- Если по paid_at есть индекс, планировщик возьмёт только нужный диапазон
- Фильтрация после агрегации заставила бы читать всю таблицу платежей за все годы
Что спросят дальше
- Спросят про пропущенные дни: нужен generate_series и LEFT JOIN, иначе в графике будут дыры
- Спросят про скользящее среднее за 7 дней: ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
- Спросят про часовые пояса: date_trunc по UTC и по Europe/Moscow дадут разные дни — для выручки это реальные деньги в отчёте
Следующая задача
Дни без продаж — Найти то, чего нет в таблице: строки нужно сначала откуда-то взять.