Нарастающий итог денежного потока
Условие
Дана таблица transactions со следующей структурой:
- date (DATE) — дата транзакции
- cash_flow (DECIMAL) — денежный поток (может быть положительным или отрицательным)
Напишите SQL-запрос для получения нарастающего итога (cumulative sum) денежного потока по дням.
Требования
- Использовать оконные функции
- Результат отсортировать по дате
Пример данных
| date | cash_flow |
|---|---|
| 2024-01-01 | 100 |
| 2024-01-02 | -50 |
| 2024-01-03 | 200 |
Ожидаемый результат
| date | cash_flow | cumulative_cf |
|---|---|---|
| 2024-01-01 | 100 | 100 |
| 2024-01-02 | -50 | 50 |
| 2024-01-03 | 200 | 250 |
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Задача требует расчета нарастающей суммы (cumulative sum) денежного потока с использованием оконных функций SQL. Это классический пример применения функции SUM() в окне с рамкой UNBOUNDED PRECEDING.
Подход к решению
Оконная функция SUM() OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) вычисляет сумму от первой строки до текущей для каждого дня.
SQL-запрос
SELECT
date,
cash_flow,
SUM(cash_flow) OVER (
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_cf
FROM transactions
ORDER BY date ASC;
Пошаговое объяснение
1. Оконная функция SUM()
- Считает сумму всех значений cash_flow от начала до текущей строки
OVER (ORDER BY date ...)— определяет окно (partition) для функции
2. Фрейм окна
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW— включает все строки с начала до текущейUNBOUNDED PRECEDING— от первой строки в результатеCURRENT ROW— включая текущую строку
3. Сортировка
ORDER BY date— последовательно идём по датам- Без этого оконные функции работают неправильно
4. Финальная сортировка
ORDER BY date ASC— выводим в хронологическом порядке
Пример выполнения
Данные:
- 2024-01-01: cash_flow = 100, cumulative = 100
- 2024-01-02: cash_flow = -50, cumulative = 100 + (-50) = 50
- 2024-01-03: cash_flow = 200, cumulative = 50 + 200 = 250
Альтернативные варианты
Вариант 1: Сокращённый синтаксис (по умолчанию)
SELECT
date,
cash_flow,
SUM(cash_flow) OVER (ORDER BY date) AS cumulative_cf
FROM transactions
ORDER BY date;
Примечание: В стандарте SQL по умолчанию при ORDER BY в OVER используется ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, поэтому можно опустить явное указание фрейма.
Вариант 2: Сортировка по дате и ID (для обработки дубликатов дат)
SELECT
date,
cash_flow,
SUM(cash_flow) OVER (
ORDER BY date, id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_cf
FROM transactions
ORDER BY date, id;
Это гарантирует правильный порядок обработки при наличии нескольких транзакций в одну дату.
Вариант 3: С партиционированием (если есть категория транзакций)
SELECT
date,
category,
cash_flow,
SUM(cash_flow) OVER (
PARTITION BY category
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_cf
FROM transactions
ORDER BY category, date;
Важные моменты
✓ ORDER BY в OVER обязателен — без него функция просто вернёт сумму всех значений для каждой строки
✓ ROWS BETWEEN ... CURRENT ROW — определяет границы окна для вычисления
✓ Отличие от GROUP BY — оконные функции не свёртывают строки, сохраняют оригинальные значения
✓ Производительность — оконные функции обычно быстрее, чем самосоединение (self-join) для больших объёмов данных
✓ Дни с нулевым потоком — если требуется вывести все дни периода (включая дни без транзакций), потребуется LEFT JOIN с календарём или COALESCE для пропущенных дней