Как посчитать time-to-convert в SQL

Проверь себя · 1/3разбор после ответа
Два запроса: SELECT * FROM orders JOIN users ON orders.user_id = users.user_id и SELECT * FROM orders JOIN users USING(user_id). В чём ключевое ограничение USING?

Зачем time-to-convert

Time-to-convert — время от первого касания до конверсии. У SaaS обычно 7–14 дней между регистрацией и первой оплатой. Если медиана растёт — цикл продаж удлиняется, что-то ломается. Если она ниже среднего по каналу — канал «горячий».

База в SQL

Простейший расчёт: регистрация → первая покупка.

WITH first_purchase AS (
    SELECT
        user_id,
        MIN(created_at) AS first_purchase_at
    FROM orders
    GROUP BY user_id
)
SELECT
    u.user_id,
    u.created_at AS signup_at,
    fp.first_purchase_at,
    EXTRACT(EPOCH FROM (fp.first_purchase_at - u.created_at)) / 86400 AS days_to_convert
FROM users u
JOIN first_purchase fp USING (user_id)
WHERE u.created_at >= CURRENT_DATE - INTERVAL '90 days';

Медиана и перцентили

Среднее искажают крупные плательщики и выбросы (пользователь купил через год). Поэтому считают перцентили:

SELECT
    COUNT(*) AS converted_users,
    AVG(days_to_convert) AS avg_days,
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY days_to_convert) AS p25,
    PERCENTILE_CONT(0.5)  WITHIN GROUP (ORDER BY days_to_convert) AS median,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY days_to_convert) AS p75,
    PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY days_to_convert) AS p95
FROM time_to_convert_per_user;

Медиана 3 дня, p95 = 30 дней — большинство быстро, хвост ходит долго.

По когортам и каналам

WITH base AS (
    SELECT
        u.user_id,
        u.utm_source AS channel,
        DATE_TRUNC('month', u.created_at)::DATE AS signup_month,
        EXTRACT(EPOCH FROM (fp.first_purchase_at - u.created_at)) / 86400 AS days
    FROM users u
    JOIN first_purchase fp USING (user_id)
    WHERE u.created_at >= CURRENT_DATE - INTERVAL '180 days'
)
SELECT
    signup_month,
    channel,
    COUNT(*) AS converted,
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days
FROM base
GROUP BY signup_month, channel
HAVING COUNT(*) >= 30
ORDER BY signup_month, median_days;

Сравните органику и платный трафик: если платный конвертит быстрее — стоит наращивать бюджет.

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

Цензурированные данные

Пользователь, который ещё не купил, не должен попадать в среднее (иначе занизит его). Учитывайте правостороннюю цензуру (right-censored):

WITH cohort AS (
    SELECT
        user_id,
        created_at,
        (SELECT MIN(created_at) FROM orders WHERE user_id = u.user_id) AS first_purchase_at
    FROM users u
    WHERE created_at >= '2026-01-01'
),
analysis AS (
    SELECT
        user_id,
        first_purchase_at IS NOT NULL AS converted,
        COALESCE(
            EXTRACT(EPOCH FROM (first_purchase_at - created_at)) / 86400,
            EXTRACT(EPOCH FROM (CURRENT_DATE - created_at)) / 86400
        ) AS time_observed
    FROM cohort
)
SELECT
    COUNT(*) FILTER (WHERE converted) AS converted_n,
    COUNT(*) FILTER (WHERE NOT converted) AS still_observing_n,
    AVG(time_observed) FILTER (WHERE converted) AS avg_among_converted_only
FROM analysis;

Для строгого анализа — Kaplan–Meier (анализ выживаемости), но это уже сложнее.

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

Ошибка 1. Среднее на асимметричных данных. Распределение time-to-convert обычно логнормальное или Weibull. Медиана честнее среднего.

Ошибка 2. Игнорировать цензурирование. Пользователь зарегистрировался 2 дня назад и не купил — это не значит, что time-to-convert = ∞. Просто «ещё не наблюдалось».

Ошибка 3. Считать через голый INNER JOIN. users INNER JOIN orders отрезает не сконвертившихся — и данные занижаются. Берите LEFT JOIN и фильтруйте дальше.

Ошибка 4. Не нормировать на возраст когорты. У пользователей из января 2026 было 4 месяца на конверсию, у майских — 13 дней. Сравнивать их без усечения окна некорректно.

Ошибка 5. Округлять до дней слишком грубо. Для SaaS с триалом и переходом на 14-й день округление до недель убьёт сигнал.

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

FAQ

Среднее или медиана?

Медиана. Распределение time-to-convert перекошено вправо: горстка пользователей, купивших спустя месяцы, тянет среднее вверх, и оно перестаёт описывать типичный срок. Медиана устойчива к таким выбросам и честнее отражает «сколько ждёт обычный пользователь».

Что делать с не сконвертившимися?

Правильный инструмент — анализ выживаемости (Kaplan–Meier): он корректно учитывает тех, кто ещё не купил, но может купить позже. Более простой вариант — считать только на закрытых когортах, у которых окно наблюдения уже полностью прошло.

Time-to-convert или цикл продаж?

Цикл продаж (sales cycle) — метрика отдела продаж: путь от лида до сделки. Time-to-convert — продуктовая метрика: от регистрации до первой покупки. Они считаются по разным событиям и живут в разных отчётах, путать их не стоит.

Какая медиана считается нормальной?

Зависит от типа продукта: у SaaS B2C это обычно 1–7 дней, у B2B — 30–90 дней, у e-commerce — 0–3 дня. Ориентир грубый: сравнивать всегда лучше со своей же прошлой когортой, а не с чужими бенчмарками.

По каналам разные медианы — что делать?

Канал с быстрой конверсией стоит масштабировать — он приводит уже прогретую аудиторию. По каналу с долгой конверсией пересмотрите CAC и окно окупаемости: деньги там возвращаются позже, и это надо закладывать в юнит-экономику.