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

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

Зачем CAGR

Бизнес часто отчитывается: «выручка выросла с 100 до 195 за 3 года». Звучит — почти двойной рост. Но это не про темп роста, а про разовый прыжок. CAGR превращает «было 100, стало 195 за 3 года» в понятную цифру: «рос на 24,9% в год в среднем» — и это уже сравнимо с другими бизнесами и с инфляцией.

Аналитика в e-commerce, fintech и SaaS постоянно просят: «дай CAGR выручки», «сравни CAGR категорий», «CAGR подписчиков по когортам». В статье — готовый SQL и подводные камни.

Что такое CAGR

CAGR (Compound Annual Growth Rate) — среднегодовой темп роста с эффектом сложного процента:

CAGR = (End / Start)^(1/years) - 1

Где:

  • Start — значение в начале периода
  • End — значение в конце
  • years — число полных лет

Пример: выручка 100 → 195 за 3 года. CAGR = (195/100)^(1/3) - 1 = 0,2493 = 24,93%/год.

Базовый расчёт

Данные: monthly_revenue(month, revenue).

WITH endpoints AS (
    SELECT
        (SELECT revenue FROM monthly_revenue ORDER BY month ASC  LIMIT 1) AS start_val,
        (SELECT revenue FROM monthly_revenue ORDER BY month DESC LIMIT 1) AS end_val,
        EXTRACT(EPOCH FROM (
            (SELECT MAX(month) FROM monthly_revenue) -
            (SELECT MIN(month) FROM monthly_revenue)
        )) / (365.25 * 24 * 3600) AS years
)
SELECT
    start_val,
    end_val,
    years,
    POWER(end_val::NUMERIC / NULLIF(start_val, 0), 1.0 / NULLIF(years, 0)) - 1 AS cagr
FROM endpoints;

Важно: start_val обязательно > 0 (иначе CAGR не определён). Если в начале периода было 0 — берите следующую ненулевую точку или используйте абсолютный прирост.

CAGR по сегментам

«Какие категории растут быстрее»:

WITH yearly AS (
    SELECT
        category,
        EXTRACT(YEAR FROM created_at) AS yr,
        SUM(revenue) AS revenue
    FROM orders
    WHERE status = 'paid'
    GROUP BY 1, 2
),
endpoints AS (
    SELECT
        category,
        MIN(yr) AS start_yr,
        MAX(yr) AS end_yr,
        MAX(yr) - MIN(yr) AS years
    FROM yearly
    GROUP BY category
),
VALUES AS (
    SELECT
        e.category,
        e.years,
        (SELECT revenue FROM yearly WHERE category = e.category AND yr = e.start_yr) AS start_val,
        (SELECT revenue FROM yearly WHERE category = e.category AND yr = e.end_yr)   AS end_val
    FROM endpoints e
)
SELECT
    category,
    start_val,
    end_val,
    years,
    POWER(end_val::NUMERIC / NULLIF(start_val, 0), 1.0 / NULLIF(years, 0)) - 1 AS cagr
FROM VALUES
WHERE years > 0
ORDER BY cagr DESC;
Закрепи формулу cagr в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать cagr в Telegram

CAGR по когортам

Как растёт средний LTV пользователей разных годов набора:

WITH cohort_ltv AS (
    SELECT
        EXTRACT(YEAR FROM signup_date) AS cohort_year,
        EXTRACT(YEAR FROM AGE(NOW(), signup_date)) AS years_since_signup,
        AVG(total_spent) AS avg_ltv
    FROM users
    WHERE total_spent > 0
    GROUP BY 1, 2
)
SELECT
    cohort_year,
    POWER(
        MAX(CASE WHEN years_since_signup = 3 THEN avg_ltv END)::NUMERIC
        / NULLIF(MAX(CASE WHEN years_since_signup = 0 THEN avg_ltv END), 0),
        1.0 / 3
    ) - 1 AS ltv_cagr_3y
FROM cohort_ltv
GROUP BY cohort_year
HAVING MAX(CASE WHEN years_since_signup = 3 THEN avg_ltv END) IS NOT NULL
ORDER BY cohort_year;

CAGR для прогноза

Если планируете значение через N лет при заданном CAGR:

SELECT
    100 AS start_revenue,
    0.20 AS expected_cagr,
    5 AS years,
    100 * POWER(1 + 0.20, 5) AS projected_revenue;
-- projected = 100 × 1.2^5 = 248.83

Полезно для «если будем расти на 20% — сколько через 5 лет».

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

Ошибка 1. Путать CAGR со средним арифметическим

Рост 10% и -5% — среднее арифметическое +2,5%. CAGR = (1.10 × 0.95)^(1/2) - 1 = 2,23%. CAGR — про реальный итог за период, среднее — про абстрактную динамику.

Ошибка 2. Делить на 0

Если start_val = 0 — формула не работает. Используйте NULLIF(start_val, 0) или явное условие.

Ошибка 3. Integer division

В PostgreSQL 1 / 3 = 0. Используйте 1.0 / 3 или 1::NUMERIC / 3.

Ошибка 4. Брать не полные годы

Период 2022-01-01 → 2023-12-31 — это 2 полных года или 1,99? Лучше пересчитать в дни → days / 365.25 для дробных лет.

Ошибка 5. CAGR на коротком периоде

CAGR на полугодии — это лукавство. Минимум 2-3 года для устойчивого среднегодового темпа.

Ошибка 6. Игнорировать сезонность

Если start_val — январь (низкий сезон), end_val — декабрь (высокий) — CAGR завышен. Берите Year-over-Year (Q4 vs Q4) или среднегодовые значения.

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

FAQ

CAGR можно считать на месячных данных?

Можно, но формула меняется: (End/Start)^(1/months) - 1 даёт CAGR в месяц. Чтобы получить годовой — умножьте на 12 при условии, что рост стабилен (что не всегда так). Лучше агрегировать до годов.

CAGR vs IRR — в чём разница?

CAGR — простой геометрический рост значения. IRR (Internal Rate of Return) — учитывает все промежуточные cash flows. CAGR — для метрик, IRR — для инвестиций.

Какой CAGR считается хорошим?

Зависит от индустрии. Зрелый ритейл — 5-10%. SaaS на ранней стадии — 100-300%. Публичные компании — 10-25%. Сравнивайте с конкурентами и инфляцией.

Что делать если CAGR отрицательный?

Это валидный результат — бизнес сжимается. Формула работает корректно: (80/100)^(1/2) - 1 = -10,5%.

Можно ли использовать AVG в SQL для CAGR?

Нет. AVG(growth) даст арифметическое среднее, которое отличается от CAGR. Только формула со степенью.