← все задачи
SQL · задача 1 из 10
Вторая по величине зарплата
Начальный
10 минут
DISTINCTLIMIT/OFFSETNULL
Условие
В таблице employees есть поле salary. Верните вторую по величине зарплату. Если такой нет — верните NULL, а не пустой результат.
Что требуется
- Одинаковые зарплаты считаются одной величиной
- При отсутствии второй зарплаты — строка с NULL
- Решение работает на таблице любого размера
Пример
salary: 100, 100, 90, 80 -> 90 salary: 100, 100 -> NULL
Сначала уточните
Вопросы до кода — половина оценки. Молча начать печатать хуже, чем задать два вопроса.
- Вторая по величине или зарплата второго сотрудника? При дубликатах это разные ответы
- Нужна ли зарплата в разрезе отделов — это уже другая задача, с оконной функцией
- Что должно вернуться при пустой таблице?
Показать решение Скрыть решение
Решение
-- Вариант 1: подзапрос гарантирует NULL вместо пустого результата
SELECT (
SELECT DISTINCT salary
FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET 1
) AS second_salary;
-- Вариант 2: через оконную функцию, если нужен и сотрудник
SELECT salary
FROM (
SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rank
FROM employees
) ranked
WHERE rank = 2
LIMIT 1;
Почему так
Почему DISTINCT обязателен
- Без него при двух одинаковых максимумах «вторая» окажется тем же числом, что и первая
- Именно на этом примере задачу и проверяют: 100, 100, 90 должно дать 90
- В варианте с рангом ту же роль играет DENSE_RANK: он не пропускает номера при дубликатах
Почему внешний SELECT вокруг подзапроса
- Запрос с LIMIT 1 OFFSET 1 на короткой таблице вернёт ноль строк, а по условию нужна строка с NULL
- Скалярный подзапрос без строк даёт именно NULL — это и требуется
- Разница между «нет строк» и «строка с NULL» ломает клиентский код, который ждёт одно значение
RANK, DENSE_RANK и ROW_NUMBER
- ROW_NUMBER нумерует подряд, дубликаты получат разные номера — для «второй величины» не подходит
- RANK при двух первых местах пропустит второе и выдаст 1, 1, 3 — второй зарплаты не найдётся
- DENSE_RANK даёт 1, 1, 2 — то, что нужно; умение выбрать нужную из трёх и есть проверка
Что спросят дальше
- Следующий вопрос почти всегда: N-я зарплата по каждому отделу — это PARTITION BY department_id
- Спросят про MAX(salary) WHERE salary < (SELECT MAX(salary)) — рабочий вариант, но два прохода по таблице
- Спросят про индекс по salary: для LIMIT 1 OFFSET 1 он превращает сортировку в чтение двух строк
Следующая задача
Топ-3 товара в каждой категории — Самая частая задача на оконные функции: «лучшие внутри группы».