Собесов

StrataScratch (Salesforce) — Retention Rates по месяцам

SQLRetentionСложнаяSenior

Условие

Таблица sf_events(account_id, user_id, record_date) — лог активности. Посчитайте retention rate для каждого account_id за декабрь 2020 → январь 2021: какая доля декабрьских юзеров активна и в январе.

Выход: account_id, retention_rate.

Формула: unique_users_in_both / unique_users_in_dec.

Решение

WITH dec_users AS (
  SELECT DISTINCT account_id, user_id
  FROM sf_events
  WHERE record_date BETWEEN '2020-12-01' AND '2020-12-31'
),
jan_users AS (
  SELECT DISTINCT account_id, user_id
  FROM sf_events
  WHERE record_date BETWEEN '2021-01-01' AND '2021-01-31'
)
SELECT
  d.account_id,
  ROUND(
    COUNT(DISTINCT j.user_id)::DECIMAL / COUNT(DISTINCT d.user_id),
    2
  ) AS retention_rate
FROM dec_users d
LEFT JOIN jan_users j
  ON j.account_id = d.account_id
 AND j.user_id    = d.user_id
GROUP BY d.account_id;

Идея

LEFT JOIN декабрьских с январскими. COUNT(DISTINCT j.user_id) посчитает только тех, кто нашёлся в обоих периодах (NULL не считается).

Альтернатива через CASE

SELECT
  account_id,
  ROUND(
    SUM(CASE WHEN active_dec AND active_jan THEN 1 ELSE 0 END)::DECIMAL
    / NULLIF(SUM(CASE WHEN active_dec THEN 1 ELSE 0 END), 0),
    2
  ) AS retention_rate
FROM (
  SELECT
    account_id, user_id,
    MAX(CASE WHEN record_date BETWEEN '2020-12-01' AND '2020-12-31' THEN 1 END) AS active_dec,
    MAX(CASE WHEN record_date BETWEEN '2021-01-01' AND '2021-01-31' THEN 1 END) AS active_jan
  FROM sf_events
  GROUP BY account_id, user_id
) t
GROUP BY account_id;

Подводные камни

  1. account_id с 0 декабрьскими пользователями. Знаменатель = 0 → деление на NULL. Через NULLIF спасаем.
  2. Один user активен в обе декабрь и в феврале (но не в январе). Не должен попадать в числитель — фильтр строго по январю.
  3. Часовой пояс. Если record_date TIMESTAMP UTC, а аналитик считает по локали — границы декабрь/январь могут «съехать».
  4. DISTINCT vs не. Если в декабре юзер активен 30 раз — это всё ещё один активный. DISTINCT user_id.

Эталонный ответ

LEFT JOIN дек/янв по (account_id, user_id) → COUNT(DISTINCT) численитель/знаменатель, NULLIF против деления на 0. Округление до 2.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти