Как посчитать воронку в SQL: шаги, конверсия и drop-off
Пошагово собираем продуктовую воронку в SQL: считаем пользователей на каждом этапе, выбираем знаменатель конверсии и находим место наибольшего отвала.

Воронка нужна не для того, чтобы раскрасить путь пользователя в несколько красивых ступеней. Её задача — показать, на каком переходе люди перестают двигаться к целевому действию. В SQL важнее всего не написать длинный запрос, а заранее определить шаги, окно анализа и знаменатель для каждой конверсии.
Коротко
Воронка — это последовательность шагов от входа в сценарий до целевого действия. Для каждого шага считаем уникальных пользователей, затем сравниваем соседние уровни. Конверсия шага и общая конверсия — разные показатели, поэтому их нельзя подписывать одним словом “conversion”.
- Сначала назови событие каждого шага и его grain.
- Для пользователей используй `COUNT(DISTINCT user_id)`.
- Локальная конверсия шага считается от предыдущего шага.
- Общая конверсия считается от первого шага воронки.
- Проверь порядок событий и временное окно между шагами.
Определи воронку до SQL
Возьмём сценарий SaaS-продукта: пользователь открыл приложение, создал проект, пригласил коллегу и выполнил core action. Один и тот же человек может повторять события, поэтому шаг воронки — это не количество строк в events, а факт того, что пользователь выполнил условие.
| Шаг | Событие | Что означает |
|---|---|---|
| 1. Вход | app_open | пользователь начал сценарий |
| 2. Проект | project_created | создал рабочий объект |
| 3. Команда | invite_sent | пригласил коллегу |
| 4. Ценность | core_action | выполнил основное действие |
Числа иллюстративные: в рабочем расчёте их нужно получить из событий с согласованным окном.
Базовый запрос: пользователи на каждом шаге
Если нужен быстрый обзор, можно посчитать уникальных пользователей, которые когда-либо совершили каждое событие в выбранном периоде. Такой запрос отвечает на вопрос “сколько людей дошло до каждого типа действия”, но ещё не доказывает, что шаги были пройдены в правильной последовательности.
select
event_name,
count(distinct user_id) as users_count
from events
where event_date >= date '2026-06-01'
and event_date < date '2026-07-01'
and event_name in (
'app_open',
'project_created',
'invite_sent',
'core_action'
)
group by event_name
order by users_count desc;Один пользователь мог выполнить core_action до app_open из выбранного периода или сделать шаги в другом сценарии. Для строгой воронки нужно проверить порядок и временную близость событий.
Последовательная воронка через первые даты
Для последовательной воронки соберём первую дату каждого шага на пользователя. Затем оставим только те строки, где даты идут в нужном порядке. Такой подход прозрачен: можно открыть одного пользователя и увидеть, почему он попал или не попал на следующий уровень.
В примере даты сравниваются только по календарному дню. Если в продукте шаги могут происходить несколько раз за день и порядок внутри дня важен, нужна timestamp-колонка или отдельный порядковый номер события. Иначе SQL не сможет восстановить реальную последовательность.
with first_steps as (
select
user_id,
min(event_date) filter (where event_name = 'app_open') as opened_at,
min(event_date) filter (where event_name = 'project_created') as project_at,
min(event_date) filter (where event_name = 'invite_sent') as invite_at,
min(event_date) filter (where event_name = 'core_action') as core_at
from events
group by user_id
),
ordered_users as (
select *
from first_steps
where opened_at is not null
and project_at > opened_at
and invite_at > project_at
and core_at > invite_at
)
select
count(*) as completed_funnel_users
from ordered_users;Локальная и общая конверсия
Пусть воронка имеет 10 000 входов, 6 200 проектов, 2 800 приглашений и 1 700 core actions. Конверсия вход → проект равна 62%, проект → приглашение — 45%, приглашение → ценность — 61%. Общая конверсия от входа до ценности — 17%. Эти числа отвечают на разные вопросы.
step_conversion = users_at_step / users_at_previous_step; total_conversion = users_at_step / users_at_first_stepЗнаменатель нужно писать рядом с метрикой в отчёте, иначе один процент легко принять за другой.
| Показатель | Формула | Вопрос |
|---|---|---|
| Локальная конверсия | step N / step N-1 | Где ломается ближайший переход? |
| Общая конверсия | step N / step 1 | Сколько входов дошло до цели? |
| Drop-off | 1 - local conversion | Какая доля потерялась на переходе? |
Окно между шагами меняет ответ
Воронка без временного окна может засчитать старое событие как часть нового сценария. Например, пользователь создал проект три месяца назад, а core action выполнил сегодня. Для онбординга это не тот же самый проход. Договорись, должен ли следующий шаг произойти в течение часа, дня или семи дней после предыдущего.
Один общий drop-off может скрывать разные сценарии. Сравни воронку по платформе, каналу, новой когорте и типу пользователя, но сначала убедись, что события одинаково трекаются в каждом сегменте.
- События одной сессии — узкое окно для коротких сценариев.
- 24 часа — часто разумный старт для активации.
- 7 или 14 дней — вариант для длинного B2B-онбординга.
- Слишком широкое окно смешивает разные попытки пользователя.
- Слишком узкое окно записывает нормальную задержку как потерю.
Ошибки в SQL-воронках
Воронка особенно чувствительна к определению события. Технический `page_view` может дать красивый первый шаг, но не сказать, что пользователь действительно начал работу. Поэтому проверяй не только запрос, но и смысл событий в продукте.
- Считать события вместо уникальных пользователей.
- Использовать разные периоды для разных шагов.
- Не фиксировать порядок событий и временное окно.
- Сравнивать локальную конверсию одного шага с общей конверсией другого.
- Менять определение шага посреди эксперимента и сравнивать несопоставимые периоды.
- Делать вывод по маленькому сегменту без показа его размера.
Мини-практика и следующий шаг
Собери в тренажёре простую воронку app_open → core_action. Сначала посчитай уникальных пользователей по типу события, затем добавь проверку порядка через первые даты. После этого сравни локальную конверсию и drop-off по каждому переходу.
Материалы по теме
Когорты и retention в SQL: как считать возвращаемость по датам
Разбираем когортный retention в SQL: как определить дату старта, посчитать D1 и D7, собрать матрицу возвращаемости и сравнить каналы без самообмана.
Читать материал
SQL CTE: как разделить сложный запрос на понятные шаги
Разбираем WITH и CTE на задачах аналитика: как сначала собрать активных пользователей, затем присоединить сегменты и проверить каждый этап расчёта.
Читать материал
Оконные функции SQL: ROW_NUMBER, LAG и накопительный итог
Как работают оконные функции SQL на задачах аналитика: найти первое событие пользователя, сравнить день с предыдущим и посчитать накопительную выручку без потери строк.
Читать материал