Как посчитать churn в SQL
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем аналитику считать churn в SQL
Churn — метрика, которую ваш CEO смотрит каждый понедельник. В SaaS churn напрямую определяет LTV: LTV = ARPU / churn. Рост churn на 1 пункт может убить unit-экономику. Поэтому умение правильно посчитать churn в SQL — обязательный навык для аналитика подписочного продукта.
Но тут много нюансов. Customer churn ≠ revenue churn. Voluntary ≠ involuntary. Monthly ≠ annual. Общий churn маскирует когортные проблемы. Если считать «в лоб», легко получить цифру, которая выглядит нормально, но скрывает реальные проблемы.
В статье — готовые SQL-запросы для всех частых случаев:
- Monthly customer churn
- Revenue churn и Net Revenue Retention (NRR)
- Churn по когортам (видно тренд улучшения продукта)
- Voluntary vs involuntary (сколько теряем из-за expired cards)
- Пересчёт monthly → annual
Вставьте в Metabase или dbt — будете считать правильно.
Формула
Churn rate = ушли за период / было в начале1. Monthly customer churn
WITH monthly AS (
SELECT
user_id,
DATE_TRUNC('month', updated_at) AS month,
status
FROM subscriptions
)
SELECT
month,
COUNT(DISTINCT user_id) FILTER (WHERE status = 'churned')::FLOAT /
NULLIF(COUNT(DISTINCT user_id), 0) AS churn_rate
FROM monthly
GROUP BY month
ORDER BY month;2. Retention-based churn
Churn = 1 - retention. Если в начале месяца было N юзеров, а на конец активны M:
WITH cohort_start AS (
SELECT user_id
FROM users
WHERE signup_at <= '2026-03-01'
AND (churned_at IS NULL OR churned_at > '2026-03-01')
),
cohort_end AS (
SELECT user_id
FROM cohort_start
WHERE user_id IN (
SELECT DISTINCT user_id FROM events WHERE event_at <= '2026-03-31'
)
)
SELECT
1.0 - COUNT(DISTINCT cohort_end.user_id)::FLOAT /
COUNT(DISTINCT cohort_start.user_id) AS churn_rate_march
FROM cohort_start
LEFT JOIN cohort_end USING (user_id);3. Revenue churn
WITH mrr_start AS (
SELECT SUM(mrr) AS mrr_start
FROM subscriptions_snapshot
WHERE snapshot_date = '2026-03-01'
),
mrr_churned AS (
SELECT SUM(s.mrr) AS mrr_lost
FROM subscriptions s
WHERE s.status = 'churned'
AND DATE_TRUNC('month', s.churned_at) = '2026-03-01'
)
SELECT
mrr_lost / mrr_start AS revenue_churn_rate
FROM mrr_start, mrr_churned;4. Net Revenue Retention (NRR)
WITH mrr_movements AS (
SELECT
SUM(CASE WHEN event_type = 'start' THEN mrr ELSE 0 END) AS new_mrr,
SUM(CASE WHEN event_type = 'expansion' THEN mrr ELSE 0 END) AS expansion,
SUM(CASE WHEN event_type = 'contraction' THEN mrr ELSE 0 END) AS contraction,
SUM(CASE WHEN event_type = 'churn' THEN mrr ELSE 0 END) AS churn
FROM mrr_events
WHERE DATE_TRUNC('month', event_at) = '2026-03-01'
),
mrr_start AS (
SELECT SUM(mrr) AS start_mrr FROM subs WHERE snapshot_date = '2026-03-01'
)
SELECT
(start_mrr + expansion - contraction - churn) / start_mrr AS nrr
FROM mrr_movements, mrr_start;NRR > 1 — рост даже без новых.
5. Churn по cohort
WITH cohorts AS (
SELECT user_id, DATE_TRUNC('month', signup_at) AS cohort
FROM users
),
activity AS (
SELECT DISTINCT user_id, DATE_TRUNC('month', event_at) AS activity_month
FROM events
)
SELECT
c.cohort,
a.activity_month,
EXTRACT(MONTH FROM AGE(a.activity_month, c.cohort)) AS months_since,
COUNT(DISTINCT a.user_id) AS active,
COUNT(DISTINCT a.user_id)::FLOAT /
(SELECT COUNT(*) FROM cohorts WHERE cohort = c.cohort) AS retention
FROM cohorts c
LEFT JOIN activity a ON a.user_id = c.user_id
GROUP BY c.cohort, a.activity_month
ORDER BY c.cohort, a.activity_month;6. Voluntary vs involuntary churn
SELECT
CASE
WHEN churn_reason IN ('card_expired', 'payment_failed') THEN 'involuntary'
ELSE 'voluntary'
END AS churn_type,
COUNT(*) AS churned
FROM subscriptions
WHERE status = 'churned'
AND DATE_TRUNC('month', churned_at) = '2026-03-01'
GROUP BY 1;7. Monthly vs annual churn
Monthly churn 5% ≠ annual 60%:
-- monthly compound → annual
SELECT 1 - POWER(1 - 0.05, 12) AS annual_churn;
-- ≈ 0.46 = 46%Частые ошибки
- Считать только по активным (survivorship bias)
- Путать customer и revenue churn
- Смешивать monthly и annual без пересчёта
- Забывать про involuntary (expired cards)
- Не учитывать cohorts
Связанные темы
FAQ
Customer или revenue churn?
Revenue для unit economics. Customer — для общей картины.
Monthly или quarterly?
SaaS с месячной оплатой — monthly. Enterprise с годовыми — annual.
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.