Как посчитать CAGR в SQL
Содержание:
Зачем 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 по когортам
Как растёт средний 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) или среднегодовые значения.
Связанные темы
- Как посчитать накопительный итог в SQL
- Оконные функции в SQL — шпаргалка
- Как посчитать MRR в SQL
- Кейс: выручка упала
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. Только формула со степенью.