Как найти вторую по величине зарплату?
Короткий ответ
Три рабочих способа: подзапрос max(salary) WHERE salary < (SELECT max(salary)); сортировка ORDER BY salary DESC с LIMIT 1 OFFSET 1; оконная функция DENSE_RANK() OVER (ORDER BY salary DESC) с фильтром = 2. Главная развилка — как считать одинаковые зарплаты: LIMIT/OFFSET даст «вторую строку», DENSE_RANK — «второй уровень значения».
Хрестоматийная задача: у неё три классических решения, и по тому, какое ты выберешь и как оговоришь ничьи, видно глубину понимания. «Правильного» одного ответа тут нет — есть правильные уточнения.
Как рассуждать
Сначала спроси: что значит «вторая» — вторая по порядку строк или второе по величине значение зарплаты? Если у максимума две ничьи (двое получают по 100), то «вторая строка» — это тоже 100, а «второе значение» — уже 90. Это разные ответы, и интервьюер обычно хочет второе значение.
Дальше выбирай инструмент под смысл:
- «максимум среди тех, кто меньше глобального максимума» — надёжно отдаёт именно второе значение;
- сортировка с пропуском первой строки (
LIMIT 1 OFFSET 1) — вернёт вторую строку, ничьи не схлопнет; - ранжирование оконной функцией — гибче всего и легко обобщается на N-ю зарплату.
Для примера на нашей схеме «зарплаты» нет, поэтому возьмём аналог — второго по тратам клиента: смысл задачи тот же.
Эталонный ответ
Способ 1 — подзапрос, «максимум ниже максимума». Явно отдаёт второе значение:
SELECT max(spend) AS second_spend
FROM (
SELECT customer_id, sum(amount) AS spend
FROM payment GROUP BY customer_id
) t
WHERE spend < (SELECT max(spend) FROM (
SELECT sum(amount) AS spend FROM payment GROUP BY customer_id
) x);
Способ 2 — сортировка с пропуском. Коротко, но вернёт вторую строку, а не второе значение (при ничьей на первом месте это может быть та же сумма):
SELECT customer_id, sum(amount) AS spend
FROM payment
GROUP BY customer_id
ORDER BY spend DESC
LIMIT 1 OFFSET 1;
Способ 3 — оконная функция, самый гибкий:
WITH ranked AS (
SELECT customer_id,
sum(amount) AS spend,
dense_rank() OVER (ORDER BY sum(amount) DESC) AS rnk
FROM payment
GROUP BY customer_id
)
SELECT customer_id, spend FROM ranked WHERE rnk = 2;
Ключевой момент — выбор ранжирующей функции. DENSE_RANK вернёт всех со «вторым по величине» значением (второй уровень). RANK при ничьей на первом месте пропустит номер 2. ROW_NUMBER даст ровно одну строку. Разница между ними — в отдельном разборе, ROW_NUMBER, RANK, DENSE_RANK.
Сильный ответ проговаривает поведение при ничьих и то, что оконный способ элементарно обобщается на N-ю зарплату заменой = 2 на нужное число.
Частые ошибки
- Дают только
LIMIT 1 OFFSET 1, не оговаривая ничьи и дубли — при равных максимумах ответ окажется неверным по смыслу. - Используют
ROW_NUMBERтам, где ждут «все со второй зарплатой», и теряют строки при ничьей. - Пишут
WHERE salary = (SELECT max(...)) - 1— предполагают шаг 1 между значениями, чего в реальных данных нет. - Забывают, что при пустой второй позиции (все зарплаты равны) запрос вернёт пусто — и не проговаривают этот крайний случай.
Потренируй этот вопрос с ИИ-интервьюером
Читать разбор полезно, а отвечать вслух под давлением — совсем другое. ИИ-интервьюер задаст этот и смежные вопросы, будет копать глубже и разберёт твои ответы. Первое короткое интервью — бесплатно.
Пройти собеседование бесплатно