Поймёте, как LAG и LEAD находят соседнее значение, посчитаете динамику по периодам и не перепутаете соседние строки разных клиентов.
Выручка в октябре — 12 млн рублей. Хорошо это или плохо? Нужна точка сравнения. Если в сентябре было 10 млн, рост равен 2 млн или 20%. LAG позволяет взять сентябрьское значение прямо в строку октября. LEAD делает обратное: показывает следующий период или событие. Это оконные функции — они не сворачивают таблицу, поэтому каждая строка остаётся на месте.
Что это значит простыми словами
Конструкция LAG(revenue) OVER (ORDER BY month) берёт revenue из предыдущей строки после сортировки по month. Для первой строки предыдущего значения нет, поэтому результат будет NULL. LEAD(revenue) работает так же, но смотрит вперёд. Второй аргумент задаёт смещение: LAG(revenue, 12) может взять значение год назад, если в данных есть ровно по одной строке на каждый месяц без пропусков.
Как работает логика
ORDER BY внутри OVER определяет, что SQL считает предыдущим. PARTITION BY разделяет расчёт на независимые группы. Для динамики по продуктам нужна конструкция LAG(revenue) OVER (PARTITION BY product_id ORDER BY month). Без PARTITION BY последняя строка одного продукта станет «предыдущей» для первого месяца другого. Стабильный порядок должен быть однозначным: для событий с одинаковым временем добавьте event_id.
Подробный пример с числами

После агрегации по месяцам есть значения 10,0 млн за сентябрь, 12,0 млн за октябрь и 11,4 млн за ноябрь. LAG возвращает NULL, 10,0 и 12,0 млн. Абсолютное изменение: revenue - prev_revenue. Получаем NULL, +2,0 и -0,6 млн. Темп: (revenue / NULLIF(prev_revenue, 0) - 1) * 100. Для октября это 20%, для ноября — -5%. NULLIF защищает деление на ноль, но решение о том, как показывать первый период, остаётся бизнес-правилом.
Сначала проверьте несколько последовательностей вручную. Число строк до и после добавления LAG должно совпасть: оконная функция не создаёт и не удаляет строки. Для каждого продукта первая дата обязана иметь prev_revenue = NULL. Если предыдущая дата перескакивает через месяц, это не ошибка LAG — в данных просто нет периода. Для календарной динамики сначала создайте полный ряд месяцев и только потом сравнивайте соседей.
Как использовать в бизнесе
LAG и LEAD полезны не только для графика выручки. Мы считаем ими время между заказами клиента, смену тарифа, переход между статусами, удержание и повторные покупки. Например, если текущий заказ сделан 20 октября, а предыдущий 5 сентября, интервал равен 45 дням. Дальше можно выделить клиентов, которые не вернулись в привычный срок, и передать список маркетингу для спокойной персональной коммуникации.
Когда применять этот подход
Используйте LAG или LEAD, когда нужны соседние строки в упорядоченной последовательности. Для общего итога по группе подойдёт SUM с GROUP BY или оконная сумма. Для первого и последнего значения окна есть FIRST_VALUE и LAST_VALUE, но у последней функции важно понимать рамку окна. Если нужно сопоставить месяцы с календарём при пропусках, одного смещения недостаточно — нужна таблица дат.
Как проверить результат

Зафиксируйте зерно до оконной функции. Если исходник содержит несколько заказов в месяц, а вы хотите месячную динамику, сначала агрегируйте их в CTE. Затем добавьте LAG. Проверьте уникальность ключа сортировки, NULL, нули и первый период. В производственном запросе сохраните предыдущую дату рядом с предыдущим значением: так пользователь увидит, с чем именно произведено сравнение.
Порядок действий
1. Определите последовательность
Решите, что является одной строкой и по какому полю идёт порядок.
2. Разделите независимые группы
Добавьте PARTITION BY для клиента, продукта или другой сущности.
3. Получите соседнее значение
Используйте LAG для прошлого и LEAD для будущего.
4. Рассчитайте разницу
Считайте абсолютное и процентное изменение с защитой от нуля.
5. Проверьте края и пропуски
Первая строка, одинаковые даты и отсутствующие периоды требуют отдельного внимания.
Ограничения и типичные ошибки
- Забывать PARTITION BY и смешивать разные сущности.
- Использовать неоднозначный ORDER BY.
- Считать LAG по сырым операциям вместо нужного уровня агрегации.
- Принимать строку со смещением за календарный месяц при пропусках.
После изменения источника или структуры таблицы повторите контрольный пример. Старое совпадение не подтверждает новую версию данных автоматически.
Как я делаю это в проектах
В проектах я вывожу пять колонок рядом: текущая дата, текущее значение, предыдущая дата, предыдущее значение и разница. Это очень приземляет расчёт. Если менеджер видит рост 20%, он сразу понимает, какие два периода сравниваются. После ручной сверки на нескольких клиентах формулу можно отдавать в дашборд. Сначала прозрачность, потом красота — схема не модная, зато рабочая (и нервы целее).
Что сделать прямо сейчас
Возьмите одну временную таблицу и добавьте предыдущую дату, предыдущее значение и абсолютное изменение. Проверьте первые три последовательности вручную.
Если хотите связать расчёт с реальным управленческим решением, можно обсудить задачу с ФАНалитикой. Начнём с одного проверяемого сценария и понятной цифры.






