Как посчитать NRR (Net Revenue Retention) в SQL

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

Что такое 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.

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

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-аналитики и опыте кандидатов.