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

Проверь себя · 1/3разбор после ответа
Вы объединяете логи событий из двух источников events_web и events_app, чтобы посчитать количество событий. Важно не потерять повторяющиеся события (например, два одинаковых клика). Что лучше использовать для объединения?

Зачем expansion MRR

Expansion MRR — рост платы от существующих клиентов за счёт перехода на более дорогой план или добавления мест (seats). В отличие от new MRR (новые клиенты), expansion дёшев в привлечении: уже привлечённый клиент просто покупает больше. Здоровый SaaS получает 30–50% всей новой выручки именно из expansion.

Что считать expansion

3 типа:

  • Апгрейд плана: Basic → Premium
  • Расширение по местам (seats): 10 → 15 пользователей
  • Рост потребления: больше API-вызовов / GB / событий

В SQL обычно сравнивают MRR клиента на конце и на начале периода: если вырос — это expansion.

Expansion в SQL

WITH start_mrr AS (
    SELECT customer_id, mrr AS start_mrr
    FROM subscription_state
    WHERE state_date = '2026-04-01' AND status = 'active'
),
end_mrr AS (
    SELECT customer_id, mrr AS end_mrr
    FROM subscription_state
    WHERE state_date = '2026-05-01' AND status = 'active'
),
both AS (
    SELECT
        s.customer_id,
        s.start_mrr,
        e.end_mrr,
        GREATEST(0, e.end_mrr - s.start_mrr) AS expansion
    FROM start_mrr s
    JOIN end_mrr e USING (customer_id)
)
SELECT
    SUM(expansion) AS total_expansion_mrr,
    COUNT(*) FILTER (WHERE expansion > 0) AS expanding_customers,
    AVG(expansion) FILTER (WHERE expansion > 0) AS avg_expansion_per_customer
FROM both;

JOIN ... USING (customer_id) отсекает новых клиентов (их нет на старте) и ушедших в отток (их нет на конце).

По типу expansion

Разделить апгрейд плана и расширение по местам:

WITH state_change AS (
    SELECT
        customer_id,
        plan_at_start,
        plan_at_end,
        seats_at_start,
        seats_at_end,
        mrr_at_start,
        mrr_at_end,
        CASE
            WHEN plan_at_end <> plan_at_start AND mrr_at_end > mrr_at_start THEN 'plan_upgrade'
            WHEN seats_at_end > seats_at_start AND plan_at_end = plan_at_start THEN 'seat_expansion'
            WHEN mrr_at_end > mrr_at_start THEN 'usage_growth'
            ELSE 'no_expansion'
        END AS expansion_type
    FROM monthly_customer_snapshot
    WHERE snapshot_month = '2026-04-01'
)
SELECT
    expansion_type,
    COUNT(*) AS customers,
    SUM(mrr_at_end - mrr_at_start) AS expansion_mrr
FROM state_change
WHERE mrr_at_end > mrr_at_start
GROUP BY expansion_type
ORDER BY expansion_mrr DESC;
Закрепи формулу expansion mrr в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать expansion mrr в Telegram

Net new MRR

Объединить с новыми продажами (new business) и contraction, чтобы получить полную картину:

SELECT
    'new_mrr' AS source,
    SUM(mrr) AS amount
FROM subscriptions
WHERE created_at >= '2026-04-01' AND created_at < '2026-05-01'

UNION ALL

SELECT
    'expansion',
    SUM(expansion)
FROM both
WHERE expansion > 0

UNION ALL

SELECT
    'contraction',
    -SUM(s.start_mrr - COALESCE(e.end_mrr, 0))
FROM start_mrr s
LEFT JOIN end_mrr e USING (customer_id)
WHERE COALESCE(e.end_mrr, 0) < s.start_mrr AND e.end_mrr > 0

UNION ALL

SELECT
    'churned',
    -SUM(s.start_mrr)
FROM start_mrr s
LEFT JOIN end_mrr e USING (customer_id)
WHERE e.end_mrr IS NULL OR e.end_mrr = 0;

Сумма всех четырёх строк = net new MRR за месяц.

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

Ошибка 1. Считать expansion на ушедших в отток. Если клиент ушёл в отток, а потом снова подписался с бо́льшим MRR — это не expansion, а win-back плюс new.

Ошибка 2. Использовать выставленный счёт вместо состояния подписки. Годовая предоплата создаст «expansion» в месяц оплаты. Нужен MRR на нормализованной помесячной шкале.

Ошибка 3. Путь A → B → A в одном периоде. Клиент понизил план, а потом вернулся на прежний — выглядит как «без изменений». В детальной аналитике важно зафиксировать оба события.

Ошибка 4. Игнорировать изменения цен. Если вы подняли цены, MRR существующих клиентов вырос — но это «pricing expansion», а не добровольный апгрейд.

Ошибка 5. Средний expansion по всей базе. Средний expansion на клиента = total_expansion / все клиенты даст заниженное число. Полезнее брать среднее только по тем, кто реально расширился.

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

FAQ

Какая доля expansion — норма?

Ориентир — 30–50% всего нового MRR. У продуктов с product-led growth (PLG) эта доля бывает и 60%+: продукт продаёт сам себя, и клиенты растут внутри без участия продавцов.

Expansion vs upsell?

По сути это про одно и то же. Upsell — термин из мира продаж (продать существующему клиенту больше), а expansion — его аналитическое отражение в метриках MRR. Разница только в том, с какой стороны вы на это смотрите.

Можно ли отрицательный expansion?

Нет, expansion по определению неотрицателен. Если MRR клиента уменьшился, это уже contraction — отдельная метрика, которую считают и трактуют иначе.

Quick ratio с expansion?

Quick Ratio показывает, насколько рост перекрывает потери: Quick Ratio = (new + expansion) / (contraction + churn). Чем выше значение, тем здоровее рост: единица означает, что вы лишь компенсируете отток, а всё, что выше, — это уже чистый рост.

Можно ли в Postgres без сложных CTE?

В простом виде — да: достаточно сравнить MRR на начало и на конец периода. Но для детального разбиения по типам expansion уже нужны snapshot-таблицы с состоянием подписок на каждую дату.