Learning Platform
Урок 09.07 · 22 мин
Средний
Practical patternsGap-and-islandCohort analysisDeduplicationCapstone

Window functions — это инструмент, который окупает себя в первые же часы реальной работы. В этом уроке — семь паттернов, которые встретятся в любом дашборде, в любой аналитической задаче. Их стоит знать наизусть и узнавать в любой формулировке клиента.

Паттерн 1: Percent of total

Доля строки в общем итоге. Один из самых частых отчётов: «какие категории дают какой процент выручки».

Доля каждого метода оплаты в общей выручке:

PostgreSQL

В классическом подходе пришлось бы дважды сканировать таблицу: один раз для агрегата, второй — для деления. С окном — один проход после агрегации.

Паттерн 2: Percent within category

Доля строки в её группе, а не в общей выборке. Например: «какую долю занимает каждый продукт в выручке своей категории».

Доля продукта в выручке своей категории (по цене × остаткам):

PostgreSQL

Единственное отличие от первого паттерна — PARTITION BY category_id в окне. Деление всегда «своя строка / своя группа».

Паттерн 3: Top-N per group

Топ-3 самых дорогих продукта в каждой категории; последние 5 заказов каждого клиента; первый платёж каждого месяца.

Топ-2 платежа по сумме для каждого клиента:

PostgreSQL

Если хочешь «N лучших с допуском равных» — замени ROW_NUMBER на RANK или DENSE_RANK. Помни: окно нельзя в WHERE, поэтому фильтр rn <= N всегда идёт в обёрточном SELECT.

Паттерн 4: Gap-and-island — острова непрерывности

Это паттерн, который восхищает с первой встречи. Задача: «найди все непрерывные периоды активности» — например, дни подряд, когда клиент логинился. «Острова» — это полосы активных дней, «промежутки» — паузы между ними.

Трюк: для каждой строки вычислить разность ROW_NUMBER по последовательности и ROW_NUMBER по фактической дате. Эта разность одинакова для всех строк одного «острова» — потому что обе последовательности растут на 1 шагом. На границе острова появляется пропуск в одной из них, и разность скачет.

Острова непрерывной активности клиента 1 по дням логинов:

PostgreSQL

Этот трюк (Mo. Itzik Ben-Gan, 2003) — один из самых эффектных способов показать, что окна — это не «ещё одна фишка SQL», а алгоритмический инструмент.

Паттерн 5: Retention cohorts

Сколько клиентов из когорты «зарегистрировались в январе» вернулись и купили в феврале, марте, и так далее. Это базовая SaaS-метрика.

Идея: для каждого клиента посчитать его первую активность (=когорта) и привязать остальные активности к этой когорте через окно.

Когортный анализ: разность между первой покупкой клиента и каждой его последующей:

PostgreSQL

В реальных дашбордах когорту обычно собирают по месяцу регистрации (date_trunc('month', signup_date)), а активность — по покупкам, и считают сводку «N клиентов из когорты M были активны на M+k месяце». Здесь — упрощённая суть.

Паттерн 6: Time-to-event / time-between-events

Сколько прошло между двумя событиями? Между логином и checkout? Между заказами одного клиента?

Время между подряд идущими заказами клиента — и среднее по клиенту:

PostgreSQL

EXTRACT(EPOCH FROM interval) превращает interval в секунды — иначе AVG над interval в PostgreSQL не работает напрямую везде. Делением на 86400 переводим в дни.

Паттерн 7: Deduplication — оставить только одну строку из дублей

Часто в реальных данных есть дубли: одна транзакция записана дважды из-за бага, или один логин логирован несколько раз. Удалить дубли по бизнес-ключу — задача, которая идеально решается через ROW_NUMBER.

Оставляем только самый ранний платёж за каждый заказ (если бы были дубли — это паттерн dedup):

PostgreSQL

Этот же паттерн используется при импорте данных: «по бизнес-ключу оставь только последнюю версию». Меняешь ORDER BY paid_at ASC на DESC — получаешь latest вместо earliest.

Бонус: совмещение нескольких паттернов

Реальные задачи редко решаются одним окном. Сложный отчёт — это связка из 2-3 окон на разных уровнях. Покажу пример: для каждого клиента — его топ-1 платёж, % этого платежа в его лайфтайм-выручке, и ранг этого клиента в общем списке по лайфтайм-выручке.

Сложный сводный отчёт — три окна сразу:

PostgreSQL

Окна вложены — но не друг в друга, а через CTE. Каждый CTE — один уровень окна. Это и есть способ строить любую аналитику любой сложности.

Проверка знанийKnowledge check
Какая задача НЕ решается одним окном и требует комбинации GROUP BY + окно? (а) Доля каждой строки в общем итоге (б) Top-N per group (в) Доля каждой группы в общем итоге (г) Running total по строкам
ОтветAnswer
(в) — «доля каждой группы в общем итоге». Шаги: сначала GROUP BY группирует данные по ключу (одна строка на группу с агрегатом), потом окно SUM(...) OVER () считает общий итог по результату агрегации, и мы делим. Одно окно это не покрывает — нужна предварительная агрегация. (а) и (г) — задачи одного окна (без GROUP BY). (б) — Top-N — это окно ROW_NUMBER плюс обёртка с фильтром, но GROUP BY не нужен.

Что унести из всего модуля 8

Window functions — это, пожалуй, самый практический инструмент в курсе. Главные пункты:

  • Окно сохраняет строки, GROUP BY коллапсирует. Это семантическое различие, не оптимизация.
  • OVER (PARTITION BY ... ORDER BY ... frame) — три необязательных компонента. Каждый меняет смысл функции.
  • Дефолтный frame с ORDER BY — running от начала до текущей. Без ORDER BY — вся партиция.
  • ROWS — по позиции; RANGE — по значению. Различие критично на дублях ORDER BY-ключа.
  • LAST_VALUE и NTH_VALUE почти всегда требуют явного frame UNBOUNDED ... UNBOUNDED.
  • Окно не работает в WHERE, GROUP BY, HAVING — фильтр по результату окна делается через CTE.
  • Агрегат внутри окна — OK. Окно внутри агрегата — нет (нужен CTE).
  • Семь паттернов: percent of total/in category, top-N per group, gap-and-island, cohorts, time-to-event, deduplication. Это уже 80% реальных задач аналитика.

В следующем модуле — рекурсивные CTE: то самое, что позволяет «гулять» по иерархиям (категории-подкатегории, менеджеры-подчинённые, дерево комментариев). Window function + recursive CTE — это уже почти полный арсенал middle-аналитика.

windowFunnel: анализ воронок в ClickHouse retention(): когортный анализ удержания в ClickHouse

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что такое паттерн gap-and-island, и какие window functions ключевые для него?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7