Как посчитать involuntary churn в SQL
events(user_id, created_at) поле created_at имеет тип отметки времени с долями секунд. Как корректно посчитать количество событий по дням?Содержание:
Зачем разделять
Voluntary churn — это когда пользователь сам отменяет подписку: продукт не оправдал ожиданий. Involuntary churn — когда подписку отменяет система из-за неудавшегося платежа (просроченная карта, нехватка средств). Лечатся они по-разному: voluntary — это работа над продуктом, involuntary — dunning и платёжная инфраструктура. Без разделения непонятно, куда вкладываться.
Voluntary vs involuntary
В таблице subscriptions обычно есть cancellation_reason:
user_cancel— voluntarypayment_failed— involuntaryexpired_grace— involuntarychargeback— involuntary
Involuntary в SQL
SELECT
COUNT(*) FILTER (WHERE cancellation_reason IN ('payment_failed', 'expired_grace', 'chargeback')) AS involuntary,
COUNT(*) FILTER (WHERE cancellation_reason = 'user_cancel') AS voluntary,
COUNT(*) AS total_churn
FROM subscriptions
WHERE churned_at BETWEEN '2026-04-01' AND '2026-04-30';Доля от всего churn
WITH stats AS (
SELECT
COUNT(*) FILTER (WHERE cancellation_reason IN ('payment_failed', 'expired_grace', 'chargeback')) AS involuntary,
COUNT(*) AS total
FROM subscriptions
WHERE churned_at >= CURRENT_DATE - INTERVAL '90 days'
)
SELECT
involuntary,
total,
involuntary::NUMERIC * 100 / NULLIF(total, 0) AS involuntary_pct
FROM stats;В индустрии involuntary обычно составляет 20-40% от всего churn. Меньше — значит, dunning настроен хорошо.
По причине
SELECT
cancellation_reason,
COUNT(*) AS churns,
SUM(mrr) AS lost_mrr,
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER () AS pct
FROM subscriptions
WHERE churned_at >= CURRENT_DATE - INTERVAL '90 days'
AND cancellation_reason IN ('payment_failed', 'expired_grace', 'chargeback', 'user_cancel')
GROUP BY cancellation_reason
ORDER BY churns DESC;Самая частая причина involuntary — это expired_grace. Лечится через сценарий обновления карты и умные повторные списания.
Частые ошибки
Ошибка 1. Считать весь churn одинаковым. Без сегментации не понять, что лечить: voluntary — это про продукт, involuntary — про биллинг.
Ошибка 2. Считать involuntary безвозвратно потерянными. 30-60% involuntary можно вернуть через dunning. Не списывайте таких пользователей сразу.
Ошибка 3. Не учитывать комиссии за chargeback. Каждый chargeback дополнительно стоит $15-25. Закладывайте это в потерянную выручку.
Ошибка 4. Считать все expired_grace как involuntary. Иногда пользователь не обновил карту намеренно — это voluntary под маской involuntary. Отделить одно от другого сложно.
Ошибка 5. Единый dunning для всех сегментов. Для enterprise работает звонок, для SMB — письмо плюс повторное списание. Методы, эффективные для SMB, не работают для enterprise, и наоборот.
Связанные темы
- Как посчитать churn в SQL
- Как посчитать MRR churn в SQL
- Как посчитать grace period recovery в SQL
- Как посчитать payment success rate в SQL
FAQ
Какой involuntary считается нормальным?
Для B2C нормой считаются 20-40% от всего churn. Для B2B Enterprise доля ниже — 5-15%, потому что там годовые контракты и меньше провалов регулярных списаний.
Как уменьшить?
Настройте умный dunning и подключите сервисы автообновления карт (например, у Stripe). Помогают и письма-напоминания об обновлении карты ещё до того, как она истечёт.
Involuntary считается в churn rate?
Обычно да, involuntary входит в общий churn rate. Но некоторые компании считают отдельную метрику net churn без involuntary, чтобы отделить продуктовый отток от платёжного.
Card updater стоит подключать?
Да, если у вас есть пользователи с высоким LTV. Stripe Card Account Updater стоит $0.25 за совпадение и окупается за счёт удержанных подписок дорогих клиентов.
Как повысить recovery rate?
Тестируйте через A/B-тесты разные цепочки dunning — тайминги писем, число попыток списания, тон сообщений. Так recovery rate реально поднять с 30% до 60%.