Задачи на рейтинг SQL на собесе
Карьерник — квиз-тренажёр в Telegram с 1500+ задач и вопросов для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем эти задачи
Ранжирование — базовая тема на собесе middle-аналитика. «Топ-3 в каждой категории», «вторая максимальная зарплата», «5-й заказ пользователя», «топ-10% клиентов по LTV» — всё это решается через ROW_NUMBER, RANK, DENSE_RANK, NTILE, PERCENT_RANK. Кто не знает разницы между ними — фейлит на первом же вопросе.
На работе такие запросы встречаются ежедневно: дашборды топ-продавцов, RFM-сегментация, выбор «свежайшего» заказа каждого пользователя, определение репитеров. Понимание семантики каждой ранжирующей функции — разница между junior и middle аналитиком.
Ниже — 10 задач с разборами. Покрывают от базовых (топ-N в таблице) до продвинутых (выдача с медалями, топ-10%, custom priority сортировки).
Задача 1. Топ-3 самых дорогих заказа
SELECT * FROM orders ORDER BY total DESC LIMIT 3;Задача 2. Топ-3 заказа в каждой категории
SELECT * FROM (
SELECT *,
DENSE_RANK() OVER (PARTITION BY category ORDER BY total DESC) AS rnk
FROM orders
) t
WHERE rnk <= 3;Задача 3. Вторая максимальная зарплата
SELECT salary FROM (
SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employees
) t
WHERE rnk = 2
LIMIT 1;Задача 4. Ранжировать пользователей по сумме заказов
SELECT
user_id,
SUM(total) AS total_spent,
DENSE_RANK() OVER (ORDER BY SUM(total) DESC) AS rank
FROM orders
GROUP BY user_id;Задача 5. Процентили клиентов
SELECT
user_id,
total_spent,
NTILE(10) OVER (ORDER BY total_spent DESC) AS decile
FROM (
SELECT user_id, SUM(total) AS total_spent
FROM orders GROUP BY user_id
) t;Задача 6. N-й заказ каждого пользователя
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at) AS order_num
FROM orders
) t
WHERE order_num = 3;Задача 7. Продавцы с top-3 товарами
SELECT DISTINCT seller_id
FROM (
SELECT *, DENSE_RANK() OVER (ORDER BY sales DESC) AS rnk
FROM products
) t
WHERE rnk <= 3;Задача 8. Первые и последние заказы каждого
SELECT
user_id,
created_at,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at) = 1 THEN 'first'
WHEN ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) = 1 THEN 'last'
ELSE 'middle'
END AS position
FROM orders;Задача 9. Топ-10% платящих клиентов
SELECT * FROM (
SELECT user_id, SUM(total) AS spend,
PERCENT_RANK() OVER (ORDER BY SUM(total) DESC) AS pr
FROM orders WHERE status = 'paid'
GROUP BY user_id
) t
WHERE pr <= 0.10;Задача 10. Ранг с кастомной сортировкой
Ранжировать по статусу (приоритет) потом по дате:
SELECT *,
RANK() OVER (
ORDER BY
CASE status WHEN 'pending' THEN 1 WHEN 'paid' THEN 2 ELSE 3 END,
created_at
) AS rnk
FROM orders;Частые ошибки
- ROW_NUMBER для топ-N с связками — вернёт неверный ответ
- Использовать в WHERE — нельзя, надо в подзапросе
- Забыть ORDER BY в OVER — неопределённый результат
Связанные темы
FAQ
ROW_NUMBER или DENSE_RANK для топ-N?
DENSE_RANK — если хотите учесть связки. ROW_NUMBER — если нужно ровно N строк.
Как быстро на больших данных?
Индекс на ORDER BY колонке. LIMIT вместо полной сортировки, если можно.
Тренируйте SQL — откройте тренажёр с 1500+ задач для собесов.