Задачи на рейтинг 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+ задач для собесов.