Как посчитать churn в SQL

Проверь себя · 1/3разбор после ответа
Вы пишете LAG(price) OVER (PARTITION BY product_id), чтобы получить «вчерашнюю цену» товара по дням. Почему результат может оказаться неожиданным?

Зачем аналитику считать churn в SQL

Churn — метрика, которую ваш CEO смотрит каждый понедельник. В SaaS churn напрямую определяет LTV: LTV = ARPU / churn. Рост churn на 1 пункт может убить unit-экономику. Поэтому умение правильно посчитать churn в SQL — обязательный навык для аналитика подписочного продукта.

Но тут много нюансов. Customer churn ≠ revenue churn. Добровольный отток ≠ вынужденный. Месячный ≠ годовой. Общий churn маскирует когортные проблемы. Если считать «в лоб», легко получить цифру, которая выглядит нормально, но скрывает реальные проблемы.

В статье — готовые SQL-запросы для всех частых случаев:

  • Monthly customer churn
  • Revenue churn и Net Revenue Retention (NRR)
  • Churn по когортам (видно тренд улучшения продукта)
  • Voluntary vs involuntary (сколько теряем из-за истёкших карт)
  • Пересчёт monthly → annual

Вставьте в Metabase или dbt — будете считать правильно.

Формула

Churn rate = ушли за период / было в начале

Churn в разных отраслях

Что считать оттоком и как его мерить, сильно зависит от продукта.

SaaS B2B. Разделяют logo churn (ушедшие клиенты) и revenue churn (потерянная выручка) — они расходятся, если уходят клиенты с нетипичным чеком. Заметную долю составляет involuntary churn из-за сбоев оплаты, и он лечится дуннингом, а не продуктом. При сильном расширении NRR может быть выше 100% даже при ненулевом оттоке.

B2C-подписки. Отток высокий и сезонный, много осознанных отписок. Фокус смещается на реактивацию спящих и перевод пользователей на годовые планы, которые механически снижают месячный churn.

Финтех и банки. Явной «отписки» нет, поэтому «ушёл» определяют поведенчески — например, нет транзакций N месяцев или обнулился баланс. От выбора этого порога сильно зависит цифра, поэтому его фиксируют в определении метрики.

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 — рост даже без новых.

Закрепи формулу churn в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать churn в Telegram

5. Churn по когортам

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,
    -- общее число месяцев между cohort и activity_month
    (EXTRACT(YEAR  FROM AGE(a.activity_month, c.cohort)) * 12
     + EXTRACT(MONTH FROM AGE(a.activity_month, c.cohort)))::INT 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

Месячный churn 5% — это не 60% в год:

-- monthly compound → annual
SELECT 1 - POWER(1 - 0.05, 12) AS annual_churn;
-- ≈ 0.46 = 46%

Примеры с собеседований

Churn на собесе проверяют на аккуратности определений.

«В чём разница user churn и revenue churn?» Сильный ответ: user churn считает долю ушедших клиентов, revenue churn — долю потерянной выручки; они расходятся, когда уходят «дорогие» или «дешёвые» клиенты непропорционально. Для unit-экономики важнее revenue churn.

«Что такое negative churn и почему это хорошо?» Сильный ответ: это когда расширение существующих клиентов перекрывает потери, то есть NRR выше 100% — выручка базы растёт без единого нового клиента. Признак сильного продукта с работающим апселлом.

«Monthly churn 5% — это сколько в год?» Не 60%. Отток компаундится: 1 − (1 − 0.05)¹² ≈ 46%. Линейное умножение на 12 — типичная ошибка. Прогнать такие вопросы с разбором можно в Карьернике.

Частые ошибки

Считать только по активным. Если базой взять тех, кто дожил до конца периода, получается survivorship bias — ушедшие выпадают из знаменателя, и churn занижается. База — это «кто мог уйти», то есть активные на начало периода.

Путать customer и revenue churn. Это разные метрики — доля ушедших клиентов и доля потерянной выручки. Для решений об unit-экономике берут revenue churn: один customer churn может скрывать, что ушли именно крупные клиенты.

Смешивать monthly и annual без пересчёта. Месячный и годовой churn нельзя сравнивать напрямую — отток компаундится, и 5% в месяц это около 46% в год, а не 60%.

Забывать про involuntary churn. Часть оттока — это не осознанный уход, а сбой оплаты из-за истёкшей карты. Его лечат дуннингом и ретраями платежей, и смешивать его с добровольным churn нельзя, иначе продуктовые выводы будут неверными.

Не учитывать когорты. Общий churn маскирует когортные проблемы: свежие слабые когорты тонут, пока средняя цифра держится за счёт старых. Разрез по когортам показывает реальный тренд.

Связанные темы

FAQ

Customer или revenue churn — что считать?

Обе метрики, но для разных задач. Revenue churn нужен для unit-экономики и оценки влияния на выручку, customer churn — для общей картины удержания. Они расходятся, когда уходят клиенты с нетипичным чеком, поэтому одну без другой смотреть рискованно.

Как выбрать период — monthly или annual?

Зависит от цикла оплаты: для SaaS с месячной подпиской естественен monthly churn, для enterprise с годовыми контрактами — annual. Главное — не сравнивать их напрямую: из-за компаундинга 5% в месяц дают около 46% в год.

Как определить churn там, где нет явной отписки?

Через поведенческий признак: пользователь считается ушедшим, если N месяцев нет активности или транзакций. Порог фиксируют в определении метрики, потому что от него напрямую зависит цифра оттока.

Как связаны churn и LTV?

Напрямую: для подписки LTV ≈ ARPU / churn, срок жизни клиента обратно пропорционален оттоку. Снижение churn с 5% до 3% в месяц увеличивает LTV почти вдвое — поэтому работа с оттоком часто даёт больше, чем рост привлечения.