Подзапросы — один из ключевых индикаторов SQL-уровня кандидата. Их знание говорит о том, что человек умеет думать многошагово: сначала получить промежуточный результат, затем использовать его в основном запросе. Именно поэтому задачи на подзапросы часто встречаются на собеседованиях аналитиков и разработчиков.
Для HR важно понимать: какие задачи давать, что считать хорошим решением и что делать, если кандидат написал что-то непохожее на эталон.
Что такое подзапрос и зачем его проверять
Подзапрос — это запрос внутри другого запроса. Простейший пример:
SELECT name
FROM users
WHERE id IN (
SELECT user_id FROM orders WHERE amount > 1000
);
Здесь внутренний SELECT — это подзапрос. Он выполняется первым и возвращает список user_id, который затем используется во внешнем запросе.
Проверка подзапросов важна потому, что:
- Они встречаются в реальной работе очень часто
- Их написание требует понимания порядка выполнения SQL
- Хорошее понимание подзапросов часто коррелирует с умением писать сложные запросы в целом
Виды подзапросов
Кандидат должен знать три вида:
1. Подзапрос в WHERE — как в примере выше, фильтрует строки.
2. Подзапрос в FROM (производная таблица) — временная таблица внутри запроса:
SELECT dept, avg_salary
FROM (
SELECT department AS dept, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
) AS dept_stats
WHERE avg_salary > 80000;
3. Коррелированный подзапрос — ссылается на внешний запрос:
SELECT name
FROM employees e
WHERE salary > (
SELECT AVG(salary) FROM employees WHERE department = e.department
);
Коррелированный подзапрос — признак продвинутого уровня.
Задачи для технического тестирования
Задача 1 — Junior
Условие: Есть таблицы products (id, name, price) и order_items (order_id, product_id, quantity). Найдите названия продуктов, которые ни разу не были заказаны.
Эталонное решение:
SELECT name
FROM products
WHERE id NOT IN (
SELECT DISTINCT product_id FROM order_items
);
Альтернативное решение (тоже правильное):
SELECT p.name
FROM products p
LEFT JOIN order_items oi ON p.id = oi.product_id
WHERE oi.product_id IS NULL;
Что оцениваем: кандидат понял задачу, использует подзапрос или LEFT JOIN. Оба подхода верны — это хороший знак.
Задача 2 — Middle
Условие: Есть таблица employees (id, name, department, salary). Найдите сотрудников, чья зарплата выше средней по их отделу.
Эталонное решение:
SELECT name, department, salary
FROM employees e
WHERE salary > (
SELECT AVG(salary)
FROM employees
WHERE department = e.department
);
Что оцениваем: кандидат использует коррелированный подзапрос. Альтернатива с CTE или JOIN — тоже хорошо.
Задача 3 — Middle+
Условие: Есть таблица orders (id, user_id, amount, created_at). Найдите пользователей, у которых сумма заказов за последний месяц превышает среднюю сумму всех пользователей за тот же период.
Эталонное решение:
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE created_at >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
AND created_at < DATE_TRUNC('month', CURRENT_DATE)
GROUP BY user_id
HAVING SUM(amount) > (
SELECT AVG(user_total)
FROM (
SELECT user_id, SUM(amount) AS user_total
FROM orders
WHERE created_at >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
AND created_at < DATE_TRUNC('month', CURRENT_DATE)
GROUP BY user_id
) AS user_sums
);
Что оцениваем: умение вложить подзапрос в HAVING, работа с датами.
Как оценивать нестандартные решения
Кандидат может решить задачу иначе, чем в эталоне. Это нормально. Попросите нанимающего менеджера проверить альтернативу на правильность. Хорошие знаки при нестандартном решении:
- Кандидат объясняет, почему выбрал именно этот подход
- Упоминает производительность («подзапрос здесь выполняется N раз, поэтому я бы предпочёл CTE»)
- Предлагает альтернативу сам
Частые ошибки кандидатов
Проблема с NULL в NOT IN
-- Ошибка: если в подзапросе есть NULL, условие не работает
WHERE id NOT IN (SELECT user_id FROM orders)
-- Правильно:
WHERE id NOT IN (SELECT user_id FROM orders WHERE user_id IS NOT NULL)
Это классическая ловушка. Кандидат, который знает о ней — явно имеет реальный опыт.
Неоправданное использование подзапроса Некоторые кандидаты пишут подзапрос там, где достаточно JOIN. Это не ошибка, но может говорить о неоптимальном мышлении.
Практический совет для HR
Попросите нанимающего менеджера отметить в каждой задаче:
- Минимально приемлемое решение (задача решена)
- Хорошее решение (задача решена правильно)
- Отличное решение (с учётом производительности)
Тогда после теста вы сможете быстро сортировать кандидатов по трём корзинам без глубокого погружения в SQL.
Итог
Задачи на подзапросы — надёжный инструмент проверки SQL-уровня. Junior должен написать подзапрос в WHERE, middle — коррелированный подзапрос, senior — объяснить trade-off между подзапросом и альтернативными подходами.