SQL
SQL задачи на собеседовании аналитика
Аналитику на собеседовании чаще дают не абстрактный синтаксис, а бизнес-вопрос: посчитать выручку, найти активных клиентов, увидеть просадку, сравнить периоды. Важно показать, как запрос превращает таблицы в вывод
Хорошая SQL-практика строится не вокруг угадывания синтаксиса, а вокруг вопроса к данным. Сначала нужно понять, какие таблицы участвуют, какая связь между ними, что фильтруем, что группируем и какой результат можно проверить глазами
Таблицы для тренировки
В примерах будем опираться на четыре таблицы:
customers(id, name, city)orders(id, customer_id, total, created_at, status)products(id, title, category, price)order_items(order_id, product_id, quantity)
Если вы тренируетесь в онлайн-тренажере, не копируйте схему буквально. Сначала найдите похожие таблицы в своей задаче: кто покупает, что покупает, где сумма, где дата, где связь между таблицами
Как работать с задачами
Перед каждым запросом запишите ожидаемый результат словами. Например: показать заказы дороже 5000, найти клиентов без заказов, посчитать продажи по городам
После запуска не смотрите только на отсутствие ошибки. Проверьте количество строк, сортировку, пустые случаи и дубли. Именно на таких проверках становится видно, понимаете ли вы запрос
Задачи с решениями
Задача 1. Сумма продаж по городам
Посчитайте выручку по городам клиентов
Решение:
SELECT c.city, SUM(o.total) AS revenue
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.city
ORDER BY revenue DESC;
Проверка: проверьте город, где есть несколько клиентов и несколько заказов
Задача 2. Количество активных клиентов
Посчитайте клиентов, у которых был хотя бы один оплаченный заказ
Решение:
SELECT COUNT(DISTINCT customer_id) AS active_customers
FROM orders
WHERE status = 'paid';
Проверка: проверьте клиента с несколькими заказами: он должен считаться один раз
Задача 3. Средний чек по городам
Посчитайте средний чек для каждого города
Решение:
SELECT c.city, AVG(o.total) AS avg_order
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'paid'
GROUP BY c.city
ORDER BY avg_order DESC;
Проверка: объясните, почему фильтр по статусу стоит до группировки
Задача 4. Повторные клиенты
Найдите клиентов с двумя и более оплаченными заказами
Решение:
SELECT customer_id, COUNT(*) AS paid_orders
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING COUNT(*) >= 2;
Проверка: проверьте клиента с одним заказом и клиента с двумя
Задача 5. Товары с самым большим спросом
Найдите товары, которые чаще всего встречаются в заказах
Решение:
SELECT p.title, SUM(oi.quantity) AS sold
FROM order_items oi
JOIN products p ON p.id = oi.product_id
GROUP BY p.id, p.title
ORDER BY sold DESC
LIMIT 10;
Проверка: проверьте товар с одинаковым количеством продаж у двух позиций
Задача 6. Выручка по дням
Посчитайте выручку по датам
Решение:
SELECT created_at, SUM(total) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY created_at
ORDER BY created_at;
Проверка: проверьте день без заказов: обычный запрос его не покажет
По этой теме полезно отдельно посмотреть SQL тренажер: как практиковаться в запросах, чтобы расширить контекст и сравнить подходы
По этой теме полезно отдельно посмотреть SQL Academy тренажер: как практиковаться, чтобы расширить контекст и сравнить подходы
Как объяснять результат
После запроса скажите, что именно означает каждая строка результата. Например: одна строка — один город, revenue — сумма оплаченных заказов, отмененные заказы исключены
Как читать готовый запрос
Начинайте с FROM: откуда берутся данные. Потом смотрите JOIN, потому что именно там часто теряются строки или появляются дубли. После этого переходите к WHERE, GROUP BY, HAVING, SELECT и ORDER BY
Если запрос длинный, запускайте его слоями: сначала одна таблица, затем соединение, затем фильтр, затем группировка. Такой порядок быстрее показывает место ошибки
Типичные ошибки
- использовать
SELECT *, когда нужны конкретные поля - забывать условие соединения в
JOIN - фильтровать агрегаты через
WHERE, хотя нуженHAVING - не проверять клиентов или товары без связанных записей
- считать строки вместо уникальных значений
- не смотреть на
NULL
Почти любую SQL-задачу можно упростить до маленькой проверки. Если результат странный, временно уберите часть условий и посмотрите, на каком шаге данные изменились не так
План практики
- Напишите пять запросов
SELECTс разными полями - Добавьте фильтры
WHERE - Потренируйте
ORDER BYиLIMIT - Перейдите к
GROUP BYи агрегатам - Добавьте
JOIN - Проверьте
LEFT JOINи отсутствующие связи - Перепишите один длинный запрос в несколько понятных шагов
Аналитический кейс
Представьте, что руководитель спрашивает: «Почему выручка выросла?» Слабый ответ — просто показать общую сумму. Сильный ответ — разложить выручку по городам, клиентам, датам и среднему чеку
Начать можно так:
SELECT
c.city,
COUNT(o.id) AS orders_count,
SUM(o.total) AS revenue,
AVG(o.total) AS avg_order
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'paid'
GROUP BY c.city
ORDER BY revenue DESC;
Этот запрос показывает не только сумму, но и количество заказов со средним чеком. Если выручка выросла из-за одного большого заказа, это будет видно по среднему. Если из-за количества заказов — по orders_count
Как защищать вывод
После запроса всегда называйте ограничения: учитываются только оплаченные заказы, города без заказов не попали в отчет, дата не фильтровалась. Такие уточнения показывают аналитическую аккуратность
Финальная самопроверка
Перед тем как считать задачу решенной, проверьте четыре вещи. Первая — не потерялись ли строки при соединении таблиц. Если в условии важны клиенты без заказов или товары без продаж, обычный JOIN может скрыть нужные строки. Вторая — не появились ли дубли после соединения. Один заказ с несколькими позициями может размножить строки, и обычный COUNT(*) начнет считать не то
Третья проверка — границы фильтра. Если написано «от 5000», уточните, входит ли сама сумма 5000. Для этого есть разница между > и >=. Четвертая проверка — смысл итоговой строки. После GROUP BY одна строка результата должна соответствовать одной группе: клиенту, городу, дню, товару или категории
Мини-задание для закрепления: возьмите любой запрос из статьи и перепишите его в два варианта — сначала через обычный JOIN, потом через LEFT JOIN. Сравните количество строк и объясните, почему результат отличается. Это упражнение быстро показывает, понимаете ли вы связь между таблицами