Пять SQL-задач для собеседования аналитика

Небольшой практический тест на данных интернет-магазина. Задачи проверяют не только синтаксис, но и умение считать правильные строки и бизнес-показатели.

SQL Studio / Разборы SQL / Пять SQL-задач для собеседования аналитика

Перед вами пять коротких задач на одной учебной базе customers, orders, payments, refunds. Попробуйте решить каждую самостоятельно в бесплатной песочнице, а затем раскрывайте решение. Установка MySQL не нужна: здесь используется SQLite; все приведённые примеры проверяются на учебной базе сайта.

Оцените себя: по одному баллу за запрос, корректный результат и объяснение ключевого ограничения. Максимум 15 баллов. Это самостоятельный ориентир, не официальная шкала собеседований.

1. Клиенты без заказов

Найдите идентификаторы и имена клиентов, у которых нет ни одного заказа. Нужно сохранить корректность при NULL в других полях.

На что обратить внимание: Отсутствие связанных строк удобно проверить через NOT EXISTS.

Показать решение и разбор
SELECT c.customer_id, c.name
FROM customers AS c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders AS o
  WHERE o.customer_id = c.customer_id
)
ORDER BY c.customer_id;

Ответ: Данил (customer_id=4). В отличие от NOT IN, вариант с NOT EXISTS не попадает в ловушку NULL при построении множества идентификаторов.

Похожее упражнение в тренажёре →

2. Доставки у каждого клиента, включая нули

Выведите customer_id и число доставленных заказов у каждого зарегистрированного клиента. Клиенты без доставок должны получить 0.

На что обратить внимание: Фильтр статуса лучше включить в условие JOIN, а COUNT(*) при LEFT JOIN здесь неверен.

Показать решение и разбор
SELECT c.customer_id,
       COUNT(o.order_id) AS deliveries_n
FROM customers AS c
LEFT JOIN orders AS o
  ON o.customer_id = c.customer_id
 AND o.status = 'delivered'
GROUP BY c.customer_id
ORDER BY c.customer_id;

Результат: (1,2), (2,1), (3,1), (4,0). Используем COUNT(o.order_id) — счётчик непустых совпавших заказов.

Похожее упражнение в тренажёре →

3. Поступления за вычетом возвратов

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

На что обратить внимание: Две отдельные агрегированные суммы безопаснее соединения двух отношений «один ко многим».

Показать решение и разбор
SELECT
  (SELECT COALESCE(SUM(amount_kopecks), 0)
   FROM payments WHERE status = 'captured')
  -
  (SELECT COALESCE(SUM(amount_kopecks), 0)
   FROM refunds) AS net_kopecks;

В учебной базе captured-платежи составляют 125000 копеек, возвраты — 9000, итог — 116000. Это учебная модель денежного итога: в реальном учёте нужны правила проведения оплат и возвратов.

Похожее упражнение в тренажёре →

4. Последний заказ каждого клиента

Получите по одному последнему заказу на клиента по дате создания. При одинаковом времени выбирайте больший order_id.

На что обратить внимание: ROW_NUMBER с PARTITION BY customer_id и дополнительным ключом сортировки.

Показать решение и разбор
WITH ranked AS (
  SELECT customer_id, order_id,
         ROW_NUMBER() OVER (
           PARTITION BY customer_id
           ORDER BY created_at DESC, order_id DESC
         ) AS rn
  FROM orders
)
SELECT customer_id, order_id
FROM ranked
WHERE rn = 1
ORDER BY customer_id;

В маленькой базе: (1,203), (2,206), (3,205). У Данила заказа нет, поэтому в этом варианте результата он не появляется.

Похожая задача: первая покупка (измените сортировку) →

5. Включить весь последний день отчёта

Получите идентификаторы заказов с 1 по 5 сентября 2026 года включительно. Столбец created_at содержит время.

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

Показать решение и разбор
SELECT order_id
FROM orders
WHERE created_at >= '2026-09-01'
  AND created_at < '2026-09-06'
ORDER BY order_id;

Ответ: 201, 202, 203, 204, 205. Использование BETWEEN до '2026-09-05' исключило бы запись с временем 15:15.

Похожее упражнение в тренажёре →

После самостоятельной проверки

Если ошиблись в задачах 1–2, повторите LEFT JOIN и NULL. Если в задаче 3 — двойной подсчёт после JOIN. Если в задаче 4 — оконные функции для последней записи. Если в задаче 5 — границы дат.


Для последовательной практики на MySQL 8 — курс «SQL для аналитика» на Stepik с итоговой работой и возможностью получить сертификат.