Как посчитать NRR (Net Revenue Retention) в SQL
Содержание:
Что такое NRR
NRR (Net Revenue Retention) — метрика SaaS, которая показывает, как изменилась выручка от существующих клиентов за период. В отличие от обычного retention, NRR считает деньги, а не подписчиков.
NRR > 100% — клиенты в среднем тратят больше, чем год назад. Это сильный сигнал для инвесторов: компания растёт даже без новых клиентов. У топ-SaaS NRR 110-130%.
NRR < 100% — выручка от существующих падает. Это churn + downgrade превышают expansion.
На собесе аналитика SaaS NRR — обязательная метрика. Спросят формулу, попросят написать SQL.
Формула
NRR = (Starting MRR + Expansion - Downgrade - Churn) / Starting MRR- Starting MRR — выручка когорты на начало периода
- Expansion — увеличение выручки от тех же клиентов (апгрейды, расширение тарифа)
- Downgrade — уменьшение тарифа без полного оттока
- Churn — выручка ушедших клиентов
Период обычно — год (annual NRR) или месяц (monthly NRR).
SQL: базовый запрос
Допустим, есть таблица subscriptions с MRR клиента по месяцам:
-- subscriptions: customer_id, month, mrr
WITH cohort AS (
-- Клиенты, которые были активны в стартовом месяце
SELECT customer_id, mrr AS starting_mrr
FROM subscriptions
WHERE month = '2025-05-01'
),
ending AS (
-- Их MRR ровно через год
SELECT customer_id, mrr AS ending_mrr
FROM subscriptions
WHERE month = '2026-05-01'
)
SELECT
ROUND(
SUM(COALESCE(e.ending_mrr, 0))::NUMERIC / NULLIF(SUM(c.starting_mrr), 0),
3
) AS nrr
FROM cohort c
LEFT JOIN ending e USING (customer_id);Главное — LEFT JOIN, а не INNER. Клиенты, которых нет через год (churned), вернут NULL → COALESCE в 0.
SQL: NRR по когортам
Если хотим NRR за каждый месяц для всех когорт:
WITH monthly_pairs AS (
SELECT
s_start.customer_id,
s_start.month AS cohort_month,
s_start.mrr AS starting_mrr,
COALESCE(s_end.mrr, 0) AS ending_mrr
FROM subscriptions s_start
LEFT JOIN subscriptions s_end
ON s_end.customer_id = s_start.customer_id
AND s_end.month = s_start.month + INTERVAL '1 year'
)
SELECT
cohort_month,
COUNT(*) AS customers_in_cohort,
ROUND(
SUM(ending_mrr)::NUMERIC / NULLIF(SUM(starting_mrr), 0),
3
) AS nrr
FROM monthly_pairs
GROUP BY cohort_month
ORDER BY cohort_month;Результат — таблица NRR по каждой когорте. Если у вас стандартная SaaS-таблица с одной строкой на клиента-месяц, эта структура работает напрямую.
Что считать «начальной выручкой»
В реальной работе NRR считают на разных видах выручки:
- Subscription MRR — только подписки
- Total MRR — подписки + add-ons
- ARR (annualized) — MRR × 12
Если используете NRR в дашборде для всей компании — берите Total MRR. Если для product team — может быть только subscription MRR без услуг.
Частые ошибки
Использовать INNER JOIN вместо LEFT JOIN. INNER исключит ушедших клиентов, и NRR будет завышен. Это самая частая и дорогая ошибка.
Не учитывать downgrade. Если клиент перешёл с $100/мес на $50/мес — это не churn, но это уменьшение MRR. NRR должен это поймать.
Считать NRR по всем активным, а не по когорте. NRR — про существующих клиентов на момент Т0. Новые клиенты, добавленные за период, в NRR не входят (для них есть GRR/новых).
Делить с integer division. 5 / 20 в Postgres = 0. Кастуйте в NUMERIC или умножайте на 1.0.
Не использовать NULLIF. Если стартовый MRR когорты = 0 (тестовая когорта) — деление на ноль уронит запрос.
FAQ
NRR vs GRR — в чём разница?
GRR (Gross Revenue Retention) — то же, но без expansion. GRR = (Starting MRR - Churn - Downgrade) / Starting MRR. GRR всегда ≤ 100%, NRR может быть > 100%.
Какой NRR считается хорошим?
Для SMB SaaS — 90-100% норма, 110% уже хорошо. Для enterprise SaaS — 110-130% стандарт, 140%+ топ.
Это официальная информация?
Нет. Статья основана на индустриальных практиках SaaS-аналитики и опыте кандидатов.