Как посчитать MRR Churn в SQL
Содержание:
Зачем MRR Churn
В SaaS-компании отвалилось 5% клиентов за месяц — кажется норма. Но revenue упала на 15%. Аналитик смотрит: отвалились enterprise-клиенты с высоким чеком, остались мелкие. Customer churn 5%, MRR churn 15%. Реальная проблема видна только через revenue-метрику.
MRR Churn — главная метрика SaaS-бизнесов. В статье — SQL и нюансы (gross vs net, customer vs revenue).
Что такое MRR Churn
MRR Churn Rate — доля MRR, потерянная за период (отказы, downgrade).
Gross MRR Churn (%) = lost MRR / MRR at start × 100%
Net MRR Churn (%) = (lost MRR - new expansion MRR) / MRR at start × 100%Net Churn может быть отрицательным — это «negative churn», когда expansion компенсирует отток. Это золотой стандарт SaaS.
Базовый расчёт
Данные: subscriptions(user_id, mrr, started_at, ended_at, status).
WITH start_mrr AS (
SELECT SUM(mrr) AS mrr_start
FROM subscriptions
WHERE started_at <= '2026-04-01'
AND (ended_at IS NULL OR ended_at >= '2026-04-01')
),
churned_mrr AS (
SELECT SUM(mrr) AS mrr_churned
FROM subscriptions
WHERE ended_at >= '2026-04-01' AND ended_at < '2026-05-01'
)
SELECT
s.mrr_start,
c.mrr_churned,
c.mrr_churned::NUMERIC / NULLIF(s.mrr_start, 0) * 100 AS gross_mrr_churn_pct
FROM start_mrr s
CROSS JOIN churned_mrr c;Важно: churn считается на начало периода, не на конец. Иначе будете занижать.
Gross vs Net Churn
WITH start_mrr AS (
SELECT SUM(mrr) AS mrr_start
FROM subscriptions
WHERE started_at <= '2026-04-01'
AND (ended_at IS NULL OR ended_at >= '2026-04-01')
),
churned AS (
SELECT SUM(mrr) AS mrr_lost
FROM subscriptions
WHERE ended_at >= '2026-04-01' AND ended_at < '2026-05-01'
),
expansion AS (
SELECT SUM(mrr_delta) AS mrr_gained
FROM subscription_upgrades
WHERE upgrade_date >= '2026-04-01' AND upgrade_date < '2026-05-01'
AND mrr_delta > 0
),
contraction AS (
SELECT SUM(ABS(mrr_delta)) AS mrr_lost_downgrade
FROM subscription_upgrades
WHERE upgrade_date >= '2026-04-01' AND upgrade_date < '2026-05-01'
AND mrr_delta < 0
)
SELECT
s.mrr_start,
c.mrr_lost + ct.mrr_lost_downgrade AS total_lost,
e.mrr_gained,
(c.mrr_lost + ct.mrr_lost_downgrade)::NUMERIC / NULLIF(s.mrr_start, 0) * 100 AS gross_churn_pct,
(c.mrr_lost + ct.mrr_lost_downgrade - e.mrr_gained)::NUMERIC / NULLIF(s.mrr_start, 0) * 100 AS net_churn_pct
FROM start_mrr s
CROSS JOIN churned c
CROSS JOIN expansion e
CROSS JOIN contraction ct;Customer vs Revenue Churn
WITH start_state AS (
SELECT
COUNT(*) AS customers_start,
SUM(mrr) AS mrr_start
FROM subscriptions
WHERE started_at <= '2026-04-01'
AND (ended_at IS NULL OR ended_at >= '2026-04-01')
),
churned AS (
SELECT
COUNT(*) AS customers_lost,
SUM(mrr) AS mrr_lost
FROM subscriptions
WHERE ended_at >= '2026-04-01' AND ended_at < '2026-05-01'
)
SELECT
s.customers_start,
s.mrr_start,
c.customers_lost,
c.mrr_lost,
c.customers_lost::NUMERIC * 100 / NULLIF(s.customers_start, 0) AS customer_churn_pct,
c.mrr_lost::NUMERIC * 100 / NULLIF(s.mrr_start, 0) AS mrr_churn_pct
FROM start_state s
CROSS JOIN churned c;Customer churn ≠ MRR churn. Если уходят высокотарифные — MRR churn выше.
MRR Churn по сегментам
WITH start_mrr_seg AS (
SELECT plan_type, SUM(mrr) AS mrr_start
FROM subscriptions
WHERE started_at <= '2026-04-01'
AND (ended_at IS NULL OR ended_at >= '2026-04-01')
GROUP BY plan_type
),
churned_seg AS (
SELECT plan_type, SUM(mrr) AS mrr_lost
FROM subscriptions
WHERE ended_at >= '2026-04-01' AND ended_at < '2026-05-01'
GROUP BY plan_type
)
SELECT
s.plan_type,
s.mrr_start,
COALESCE(c.mrr_lost, 0) AS mrr_lost,
COALESCE(c.mrr_lost, 0)::NUMERIC * 100 / NULLIF(s.mrr_start, 0) AS churn_pct
FROM start_mrr_seg s
LEFT JOIN churned_seg c ON c.plan_type = s.plan_type
ORDER BY churn_pct DESC;Частые ошибки
Ошибка 1. Считать на начало или на конец? Только на начало периода. На конец будет иное.
Ошибка 2. Включать новых, которые в этом же месяце отвалились. Если клиент пришёл 3 апреля и ушёл 25 апреля — это churn? В стандартной логике — нет, он не был в MRR на начало. Но «micro-churn» нужно отдельно отслеживать.
Ошибка 3. Расчёт annualised.
Monthly churn 3% × 12 ≠ 36% annual. Правильно: 1 - (1-monthly)^12 = 1 - 0,97^12 ≈ 30,6%.
Ошибка 4. Игнорировать downgrade. Customer не ушёл, перешёл с $100 на $30 — это $70 contraction MRR.
Ошибка 5. NULL в ended_at.
Active subscription имеет ended_at IS NULL. Не путать с пропавшими данными.
Ошибка 6. Не различать voluntary vs involuntary churn. Voluntary — клиент сам отписался. Involuntary — карта не прошла платёж. Разные причины, разный fix.
Связанные темы
- Как посчитать MRR в SQL
- Как посчитать NRR в SQL
- Как посчитать churn в SQL
- Как посчитать retention в SQL
FAQ
Какой MRR Churn считается хорошим?
В SaaS B2B: 0,5-1% monthly = отлично, 2-3% = средне, 5%+ = проблема. В SaaS B2C: 3-7% — норма.
Net Churn может быть отрицательным?
Да, и это лучшее, что может быть. Negative net churn значит, что expansion (рост существующих) превышает отток.
Когда smотреть customer, когда MRR churn?
Customer — про retention клиента. MRR — про revenue. В энтерпрайзе MRR важнее.
Voluntary vs involuntary?
Voluntary — клиент сам ушёл (плохой fit, переход к конкуренту). Involuntary — техническая (карта не прошла, банк блокировал). Решаются разными командами.
Annual MRR churn = monthly × 12?
Нет. Annual = 1 - (1-monthly)^12. Для 3% monthly = 30,6% annual, не 36%.