Как посчитать CSAT по типам обращений в SQL

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

Зачем разбивка CSAT

Один общий CSAT 85% ничего не говорит, какие именно категории тикетов разочаровывают клиентов. Разбивка по issue type показывает, где self-service не работает, где агенты слабее, где продукт реально ломается. Insights → roadmap для product team или training.

Базовая разбивка

SELECT
    issue_category,
    COUNT(*) AS surveys_received,
    AVG(csat_score) AS avg_csat,
    COUNT(*) FILTER (WHERE csat_score >= 4) * 100.0
    / NULLIF(COUNT(*), 0) AS satisfied_pct
FROM csat_surveys
WHERE survey_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY issue_category
HAVING COUNT(*) >= 30
ORDER BY avg_csat ASC;

HAVING COUNT(*) >= 30 отсекает категории с шумным сэмплом.

Worst-performing категории

WITH baseline AS (
    SELECT AVG(csat_score) AS overall_csat FROM csat_surveys
    WHERE survey_date >= CURRENT_DATE - INTERVAL '30 days'
)
SELECT
    s.issue_category,
    AVG(s.csat_score) AS category_csat,
    b.overall_csat,
    AVG(s.csat_score) - b.overall_csat AS gap_vs_overall,
    COUNT(*) AS n
FROM csat_surveys s, baseline b
WHERE s.survey_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY s.issue_category, b.overall_csat
HAVING COUNT(*) >= 30
ORDER BY gap_vs_overall ASC
LIMIT 10;

Категории с CSAT < baseline на 1+ балл — приоритет для root cause analysis.

По агенту и категории

SELECT
    agent_id,
    issue_category,
    AVG(csat_score) AS avg_csat,
    COUNT(*) AS n
FROM csat_surveys
WHERE survey_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY agent_id, issue_category
HAVING COUNT(*) >= 20
ORDER BY agent_id, avg_csat ASC;

Агент, у которого все категории кроме одной OK — нужен тренинг по этой одной.

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

Динамика

SELECT
    DATE_TRUNC('week', survey_date)::DATE AS week,
    issue_category,
    AVG(csat_score) AS avg_csat
FROM csat_surveys
WHERE survey_date >= CURRENT_DATE - INTERVAL '12 weeks'
  AND issue_category IN ('billing', 'technical', 'feature_request')
GROUP BY DATE_TRUNC('week', survey_date), issue_category
ORDER BY week, issue_category;

Падение CSAT в одной категории на 2-3 недели — signal release-проблемы.

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

Ошибка 1. Усреднять без normalize sample. Если billing — 80% тикетов, его CSAT доминирует в общем. Сегментируйте.

Ошибка 2. Survey selection bias. Только 10-30% юзеров отвечают на survey. Те, кто недоволен — чаще. CSAT systematically lower than reality.

Ошибка 3. Игнорировать low-response категории. Категории с 5-10 surveys — шум. HAVING COUNT(*) >= 30.

Ошибка 4. Считать только closed tickets. Включайте also abandoned tickets (no resolution → likely low CSAT). Без них bias.

Ошибка 5. CSAT vs NPS confusion. CSAT = satisfaction по конкретному ticket. NPS = overall recommendation. Не путать.

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

FAQ

Какой CSAT хороший?

4.2-4.5 / 5 — отличный. 3.8-4.2 — норма. < 3.5 — проблема.

Survey selection bias лечить?

Random sample 100% тикетов. Если selection — sweepstake для всех ответивших.

CSAT через email?

Часто бывает — embedded survey в follow-up email. 5-10% response rate.

Per-agent или per-category?

Оба. Agent — for training, category — for product.

Сколько response rate нормально?

10-25% для email. 30-50% для in-product survey.