SQL для аналитика: запрос — ещё не вывод

Задача аналитика не просто получить таблицу, а объяснить, что означают цифры, как они посчитаны и можно ли им доверять.

SQL Studio / Разборы SQL / SQL для аналитика: запрос — ещё не вывод

Начинайте с вопроса бизнеса

«Сколько у нас покупателей?» — неполный вопрос. Покупатель за всё время, за месяц, с оплаченным заказом или с доставленным заказом? Пока это не определено, даже безошибочный SQL может дать неверный ответ.

Определите единицу подсчёта

Для расчёта конверсии клиентов в покупателей числитель и знаменатель должны относиться к одной аудитории и периоду наблюдения. Один клиент может сделать несколько заказов, но для конверсии он обычно учитывается один раз.

WITH buyers AS (
  SELECT DISTINCT customer_id
  FROM orders
  WHERE status = 'delivered'
)
SELECT
  COUNT(*) AS customers_n,
  COUNT(b.customer_id) AS buyers_n,
  ROUND(100.0 * COUNT(b.customer_id) /
        NULLIF(COUNT(*), 0), 2) AS conversion_pct
FROM customers AS c
LEFT JOIN buyers AS b
  ON b.customer_id = c.customer_id;

На нашей базе результат: 4 зарегистрированных клиента, 3 покупателя с доставкой, 75%. Это доля зарегистрированных клиентов с доставкой за доступную историю, а не конверсия сессий или рекламного канала.

Проверяйте деньги и связи таблиц

В аналитике интернет-магазина различайте созданные заказы, оплаченные суммы, возвраты и чистые продажи. При соединении заказов с позициями важно проверять уровень детализации, иначе отчёт может завысить суммы.

SQLite в тренажёре и MySQL 8 в отдельном курсе

SQL Studio исполняет бесплатные задания на SQLite в вашем браузере. Отдельный авторский курс Stepik использует MySQL 8 и заканчивается аналитическим отчётом. Знания о ключах JOIN, NULL, агрегациях и гранулярности переносятся, но синтаксис не всегда переносим буквально.

ЗадачаSQLite (SQL Studio)MySQL 8 (курс)
Прибавить семь днейdate(created_at, '+7 day')DATE_ADD(created_at, INTERVAL 7 DAY)
Месяц в YYYY-MMstrftime('%Y-%m', created_at)DATE_FORMAT(created_at, '%Y-%m')
Строки склеитьfirst_name || ' ' || last_nameCONCAT(first_name, ' ', last_name)
ДеньгиINTEGER в копейкахDECIMAL(p,s) с явно заданной точностью или целые копейки
Нумерация по группеROW_NUMBER() OVER (...)ROW_NUMBER() OVER (...)

SQLite имеет динамические правила типов и преобразований, MySQL 8 — иные типы и настройки SQL mode. Для дат в MySQL DATETIME и TIMESTAMP различаются по поведению часового пояса. В обоих движках оконный ORDER BY не гарантирует порядок конечных строк без внешнего ORDER BY. Перед переносом отчёта сверяйте результаты, NULL, округление, индексы и временную зону на настоящем движке.

Что можно написать в выводе

«Трое из четырёх зарегистрированных клиентов имеют доставленный заказ — 75%». Нельзя писать «75% посетителей конвертировались благодаря рекламе»: у нас нет ни сессионного знаменателя, ни доказательств влияния рекламного канала.

Пример конкретной бизнес-метрики: повторные покупки, доля возвращающихся клиентов и ограничения знаменателя.