← Назад к вопросам

Нарастающий итог денежного потока

2.2 Middle🔥 151 комментариев
#SQL и базы данных#Метрики и KPI

Условие

Дана таблица transactions со следующей структурой:

  • date (DATE) — дата транзакции
  • cash_flow (DECIMAL) — денежный поток (может быть положительным или отрицательным)

Напишите SQL-запрос для получения нарастающего итога (cumulative sum) денежного потока по дням.

Требования

  • Использовать оконные функции
  • Результат отсортировать по дате

Пример данных

datecash_flow
2024-01-01100
2024-01-02-50
2024-01-03200

Ожидаемый результат

datecash_flowcumulative_cf
2024-01-01100100
2024-01-02-5050
2024-01-03200250

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Задача требует расчета нарастающей суммы (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 для пропущенных дней

Нарастающий итог денежного потока | PrepBro