Как посчитать bad debt rate в SQL

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

Зачем bad debt rate

Bad debt rate — доля выручки, которую компания не получает (списания, банкротства customer, fraud chargeback). Прямой удар по прибыли. Финансовый стандарт 0.5-1.5% для B2C, 1-3% для B2B SMB, 0.1-0.5% для enterprise. Резкий рост — flag credit policy issues.

Формула

bad_debt_rate = written_off / total_revenue_billed

Period обычно — квартал или год.

Bad debt в SQL

WITH revenue AS (
    SELECT SUM(amount) AS total_billed
    FROM invoices
    WHERE billed_at >= '2025-01-01' AND billed_at < '2026-01-01'
),
write_offs AS (
    SELECT SUM(amount) AS total_written_off
    FROM bad_debt_writeoffs
    WHERE writeoff_date >= '2025-01-01' AND writeoff_date < '2026-01-01'
)
SELECT
    (SELECT total_billed FROM revenue) AS billed,
    (SELECT total_written_off FROM write_offs) AS written_off,
    (SELECT total_written_off FROM write_offs)::NUMERIC * 100
    / NULLIF((SELECT total_billed FROM revenue), 0) AS bad_debt_rate_pct;

Динамика

SELECT
    DATE_TRUNC('month', billed_at)::DATE AS month,
    SUM(amount) AS revenue,
    SUM(amount) FILTER (WHERE status = 'written_off') AS written_off,
    SUM(amount) FILTER (WHERE status = 'written_off')::NUMERIC * 100
    / NULLIF(SUM(amount), 0) AS bad_debt_pct
FROM invoices
WHERE billed_at >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY DATE_TRUNC('month', billed_at)
ORDER BY month;

Растущий тренд = credit policy ослаб. Падающий = collections команда работает.

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

По сегменту customer

SELECT
    customer_segment,
    COUNT(DISTINCT i.invoice_id) AS invoices,
    SUM(i.amount) AS revenue,
    SUM(i.amount) FILTER (WHERE i.status = 'written_off') AS bad_debt,
    SUM(i.amount) FILTER (WHERE i.status = 'written_off')::NUMERIC * 100
    / NULLIF(SUM(i.amount), 0) AS bad_debt_pct
FROM invoices i
JOIN customers c USING (customer_id)
WHERE i.billed_at >= CURRENT_DATE - INTERVAL '6 months'
GROUP BY customer_segment
HAVING COUNT(*) >= 100
ORDER BY bad_debt_pct DESC;

SMB обычно 1-3%, Enterprise меньше 0.5%. Если SMB свыше 5% — review credit policy.

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

Ошибка 1. Bad debt vs delinquent. Delinquent — late payment, ещё не списан. Bad debt — списано (no expectation of recovery).

Ошибка 2. Игнорировать recovery. Часть write-offs восстанавливается через коллекторов. Net bad debt = written_off − recovered.

Ошибка 3. Не нормировать на revenue. Absolute write-off 1M$ — много или мало? Зависит от revenue.

Ошибка 4. По всему customer base. New customers (без credit history) имеют выше bad debt. Сегментируйте.

Ошибка 5. Counts vs amounts. 1 enterprise customer написать на $50k = 1 case, но материально больше 100 SMB cases по $500.

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

FAQ

Какой bad debt норма?

B2C SaaS 0.5-1.5%. B2B SMB 1-3%. Enterprise меньше 0.5%.

Bad debt vs allowance for doubtful accounts?

Allowance = reserve (estimated future bad debt). Bad debt = actual write-off.

Когда списывать?

US GAAP: после 90-180 days past due. Зависит от accounting policy.

Можно ли zero bad debt?

Только если strict credit (pre-paid). Тогда теряете customers, кто бы платил.

Tracking recovery?

Yes — отдельная таблица bad_debt_recoveries. Net = gross write-off − recovery.