Тридцать минут — стандартный слот для технического скрининга. Этого вполне достаточно, чтобы понять реальный уровень SQL-навыков кандидата. Главное — не тратить время на вопросы «что такое реляционная база данных», а сразу перейти к практике.
Структура 30-минутного скрининга
| Время | Блок | Цель |
|---|---|---|
| 0–5 мин | Контекст | Узнать, с какими данными работал |
| 5–20 мин | Практические задачи | Проверить навыки написания запросов |
| 20–28 мин | Разбор решений | Понять ход мыслей |
| 28–30 мин | Вопросы кандидата | Оценить интерес к роли |
Блок 1: Контекст (5 минут)
Начните с открытых вопросов о реальном опыте:
- «Расскажите о последнем сложном SQL-запросе, который вы писали»
- «С какими объёмами данных работали? Миллионы строк? Миллиарды?»
- «Какую СУБД использовали чаще всего?»
По ответам вы уже сориентируетесь в уровне: Junior расскажет про SELECT с WHERE, Senior — про оптимизацию планов выполнения.
Блок 2: Практические задачи (15 минут)
Задача 1 — 3 минуты (базовый уровень)
Дайте схему двух таблиц и попросите написать запрос:
-- Таблицы: employees(id, name, department_id, salary)
-- departments(id, name, city)
-- Задача: найдите среднюю зарплату по каждому городу,
-- отсортируйте по убыванию
SELECT
d.city,
ROUND(AVG(e.salary), 2) AS avg_salary
FROM employees e
JOIN departments d ON d.id = e.department_id
GROUP BY d.city
ORDER BY avg_salary DESC;
Что проверяем: умение JOIN двух таблиц, GROUP BY, агрегация, ORDER BY.
Задача 2 — 5 минут (средний уровень)
-- Таблица: orders(id, customer_id, amount, created_at)
-- Задача: для каждого клиента найдите его первый и последний заказ,
-- а также общую сумму. Покажите только клиентов, сделавших 3+ заказа
SELECT
customer_id,
MIN(created_at) AS first_order,
MAX(created_at) AS last_order,
SUM(amount) AS total_amount,
COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
HAVING COUNT(*) >= 3;
Что проверяем: несколько агрегатных функций, HAVING.
Задача 3 — 7 минут (продвинутый уровень)
-- Таблица: sessions(user_id, session_date, duration_sec)
-- Задача: для каждого пользователя найдите сессию,
-- в которой длительность была максимальной за всё время.
-- Если таких сессий несколько — взять самую раннюю.
SELECT DISTINCT ON (user_id)
user_id,
session_date,
duration_sec
FROM sessions
ORDER BY user_id, duration_sec DESC, session_date ASC;
Альтернативное решение через оконные функции (принимаем оба):
SELECT user_id, session_date, duration_sec
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY duration_sec DESC, session_date ASC
) AS rn
FROM sessions
) t
WHERE rn = 1;
Блок 3: Разбор решений (8 минут)
Попросите кандидата объяснить своё решение вслух. Ключевые вопросы:
«Почему вы выбрали именно такой подход?» — Понимает ли кандидат альтернативы?
«Что произойдёт, если в таблице миллиард строк?» — Думает ли о производительности?
«Как можно улучшить этот запрос?» — Есть ли самокритика и стремление к оптимальности?
Сигналы хорошего кандидата
- Уточняет требования перед написанием запроса («А NULL-значения возможны?»)
- Думает вслух, объясняет ход рассуждений
- Предлагает несколько способов решения
- Сразу думает об индексах при работе с большими таблицами
- Замечает edge cases (пустые таблицы, NULL, дубликаты)
Сигналы слабого кандидата
- Сразу пишет
SELECT *без объяснения - Не знает разницы между WHERE и HAVING
- Не может объяснить написанный код
- Отказывается рассуждать вслух («мне нужно время подумать самому»)
- Путается в порядке выполнения SQL-операций
Чеклист оценки
После скрининга заполните короткую форму:
| Критерий | 0 | 1 | 2 |
|---|---|---|---|
| Базовые запросы (SELECT, WHERE, JOIN) | не знает | знает теорию | пишет уверенно |
| Агрегация (GROUP BY, HAVING) | |||
| Подзапросы / CTE | |||
| Оконные функции | |||
| Понимание производительности |
Итого из 10: Junior ≥ 4, Middle ≥ 7, Senior ≥ 9.
Рекомендуйте кандидатам подготовиться к техническому интервью на SQLlab.ru — там именно такие задачи с мгновенной проверкой в браузере.