Как найти самого высокооплачиваемого сотрудника в каждом отделе?
Таблица Employee(id, name, dept_id, salary). Верните полную строку самого высокооплачиваемого сотрудника в каждом отделе.
Требования:
- одна строка результата на отдел, с
idиname(а не только зарплата) - ранжирование внутри отдела, а не глобально — обычный
GROUP BY+MAXне вернёт имя - при совпадении на вершине допустимо вернуть ровно одну строку
SELECT id, name, dept_id, salary
FROM Employee
-- ваш запрос здесь
Напишите запрос.
Пронумеруйте строки по отделу через ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) в подзапросе, затем оставьте WHERE rn = 1. PARTITION BY сбрасывает ранжирование для каждого отдела, поэтому строка 1 — топ отдела. Альтернатива — коррелированный подзапрос по MAX(salary) на отдел.
- ✗Использовать
GROUP BY dept_id+MAX(salary)и ждать, что имя сотрудника подтянется - ✗Ранжировать глобально без
PARTITION BY dept_id - ✗Использовать
LIMIT 1и получить топ только одного отдела
- →Чем
PARTITION BYотличается отGROUP BYпо тому, что возвращает? - →Когда предпочесть
RANKвместоROW_NUMBERпри совпадениях на вершине отдела?
Задача
Найти самого высокооплачиваемого сотрудника в каждом отделе.
-- Через оконную функцию
SELECT id, name, dept_id, salary
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM Employee
) t
WHERE rn = 1;
-- Через коррелированный подзапрос
SELECT *
FROM Employee e
WHERE salary = (SELECT MAX(salary) FROM Employee x WHERE x.dept_id = e.dept_id);
Как это работает
Это паттерн «top-N на группу». ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) нумерует строки внутри каждого отдела: PARTITION BY перезапускает счёт для каждого dept_id, а ORDER BY salary DESC ставит самую большую зарплату первой. Внешний WHERE rn = 1 оставляет лидера каждого отдела — со всеми его столбцами (id, name).
Преимущество над GROUP BY dept_id + MAX(salary): группировка вернёт максимум, но не скажет, кому он принадлежит (имя нельзя выбрать без агрегата). Оконная функция сохраняет всю строку.
⚠️ При совпадениях на вершине ROW_NUMBER оставит ровно одного; используйте RANK, если нужны все с максимумом.