Выручка по месяцам и рост к предыдущему месяцу
Классика собеседований на аналитика: месячная динамика с ростом в процентах. Простая по идее, но в ней спрятаны три аккуратности, на которых валятся.
Задача
Есть таблица заказов orders(order_id, amount, created_at). Посчитай выручку по месяцам и рост к предыдущему месяцу в процентах.
Схема данных
CREATE TABLE orders (
order_id int,
amount numeric,
created_at timestamp
);
Заказы разбросаны по нескольким месяцам — их нужно сгруппировать по месяцу и посчитать сумму, а потом сравнить каждый месяц с предыдущим.
Решение
WITH monthly AS (
SELECT date_trunc('month', created_at) AS month, SUM(amount) AS revenue
FROM orders
GROUP BY 1
)
SELECT to_char(month, 'YYYY-MM') AS month, revenue,
ROUND(100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
/ NULLIF(LAG(revenue) OVER (ORDER BY month), 0), 1) AS growth_pct
FROM monthly
ORDER BY month;
Разбор
Сначала сводим заказы к месячной выручке. date_trunc('month', created_at) обрезает дату до первого числа месяца — так все заказы одного месяца попадают в одну группу, и SUM(amount) даёт месячную выручку. Во внешнем запросе результат оборачиваем в to_char(month, 'YYYY-MM') — это только для читаемого вывода, а группировка, LAG и ORDER BY внутри работают с исходной датой.
Дальше рост считает оконная функция LAG(revenue) OVER (ORDER BY month): она подтягивает выручку предыдущего по порядку месяца. Формула роста — (текущий − предыдущий) / предыдущий, в процентах.
И вот три аккуратности, ради которых задачу и дают:
100.0, а не100. Если умножать на целое и делитьnumericнаnumeric, в некоторых движках получишь целочисленное деление и потеряешь дробную часть.100.0гарантирует дробную арифметику.NULLIF(..., 0)в знаменателе. Если у предыдущего месяца выручка вдруг ноль — деление упадёт.NULLIFпревращает ноль вNULL, и вместо ошибки получаемNULL.- Первый месяц. У него нет предыдущего,
LAGвернётNULL, и рост честно окажетсяNULL— сравнивать не с чем.
ORDER BY month во внешнем запросе выводит месяцы по порядку. Про то, как окно смотрит в соседнюю строку, — в вопросе что такое оконные функции.
Ожидаемый результат
month | revenue | growth_pct
--- | --- | ---
2026-01 | 1000 | NULL
2026-02 | 1500 | 50.0
2026-03 | 1200 | -20.0
2026-04 | 1800 | 50.0
2026-05 | 900 | -50.0
Прорешай такие задачи сам
Читать разбор полезно, а настоящая прокачка — самому писать запросы и получать обратную связь. В симуляторе живая база и проверка запросов, лёгкий режим — бесплатно.
Прорешать в бесплатной песочнице