Как посчитать Returning Users в SQL
Содержание:
Зачем Returning Users
DAU 100K — кажется хорошо. Но: 70K new, 30K returning. Через месяц new падает (закончилась реклама), DAU становится 30K. Returning ratio — здоровый сигнал sustainability бизнеса.
Что такое Returning
Returning User — активный за период, чья первая активность была ДО начала периода.
Returning ∈ period: first_activity < period_start AND has_activity_in_periodБазовый расчёт
WITH first_activity AS (
SELECT user_id, MIN(event_date) AS first_date
FROM events
GROUP BY user_id
)
SELECT
DATE_TRUNC('month', e.event_date) AS month,
COUNT(DISTINCT CASE
WHEN fa.first_date < DATE_TRUNC('month', e.event_date)
THEN e.user_id
END) AS returning_users,
COUNT(DISTINCT CASE
WHEN fa.first_date >= DATE_TRUNC('month', e.event_date)
AND fa.first_date < DATE_TRUNC('month', e.event_date) + INTERVAL '1 month'
THEN e.user_id
END) AS new_users,
COUNT(DISTINCT e.user_id) AS total_active
FROM events e
JOIN first_activity fa ON fa.user_id = e.user_id
WHERE e.event_date >= '2026-01-01'
GROUP BY 1
ORDER BY 1;Returning vs New vs Reactivated
| Тип | Определение |
|---|---|
| New | Первая активность ∈ period |
| Returning | Был активен сразу до period |
| Reactivated | Был активен давно, потом был неактивен X+ дней, вернулся в period |
WITH user_state AS (
SELECT
user_id,
MIN(event_date) AS first_date,
MAX(CASE WHEN event_date < '2026-04-01' THEN event_date END) AS last_before_period,
MIN(CASE WHEN event_date >= '2026-04-01' AND event_date < '2026-05-01' THEN event_date END) AS first_in_period
FROM events
GROUP BY user_id
)
SELECT
CASE
WHEN first_date >= '2026-04-01' AND first_date < '2026-05-01' THEN 'new'
WHEN last_before_period >= '2026-03-01' THEN 'returning'
WHEN last_before_period IS NOT NULL THEN 'reactivated'
END AS user_type,
COUNT(*) AS users
FROM user_state
WHERE first_in_period IS NOT NULL
GROUP BY 1;Разрезы
По segments / channels:
SELECT
u.acquisition_channel,
COUNT(DISTINCT CASE
WHEN MIN(e.event_date) OVER (PARTITION BY e.user_id) < DATE_TRUNC('month', CURRENT_DATE)
THEN e.user_id
END) AS returning_users
FROM events e
JOIN users u ON u.user_id = e.user_id
WHERE e.event_date >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY u.acquisition_channel;Частые ошибки
Ошибка 1. Returning = всё, что не new. В этой логике reactivated засчитывается как returning. Различайте.
Ошибка 2. Boundary issues. Юзер с first_date = period_start — это new или returning? Договоритесь.
Ошибка 3. Cross-device. Без unified user_id новый device = «new». Учитывайте.
Ошибка 4. NOT IN с NULL. Ломается. Используйте NOT EXISTS.
Ошибка 5. Сравнение returning across periods без normalization. Юзер в апреле = «returning» если был активен в марте. В мае может стать «reactivated» если в апреле не зашёл. Состояние user-type меняется по периодам.
Связанные темы
- Как посчитать new users в SQL
- Как посчитать reactivation в SQL
- Как посчитать retention в SQL
- Как посчитать DAU в SQL
FAQ
Returning vs Reactivated?
Returning — был активен недавно (< lapse threshold). Reactivated — вернулся после долгого отсутствия.
Какой Returning ratio хороший?
Зависит от growth-стадии. Стартап в hyper-growth: new > returning. Зрелый продукт: returning >> new.
Returning DAU падает — что делать?
Скорее всего проблема в retention или engagement. Декомпозиция по cohort.
Cross-device — обязательно?
Желательно. Без unification — overcount new и undercount returning.
Returning стабильный, new упал — что делать?
Проблема в acquisition (маркетинг / SEO). Returning — здоровая база.