Как выбрать всех сотрудников с максимальной зарплатой в каждом департаменте с именем, зарплатой и названием департамента в SQL?
Что проверяют
Умеете ли вы достать из группы не только агрегат, но и строку целиком. MAX с GROUP BY даёт число, а имя сотрудника к нему просто так не приклеить. Следом почти всегда спрашивают, что будет, если максимум делят двое, и как этот запрос живёт в Java-коде.
Как отвечать
Сначала уточните схему: обычно это employees(id, name, salary, department_id) и departments(id, name), так что название департамента берётся джойном. Дальше покажите рабочие способы:
- подзапрос с агрегатом: считаете
MAX(salary)поdepartment_idв подзапросе, джойните его сemployeesпо паре «департамент и зарплата», затем сdepartments. Работает в любой СУБД и возвращает всех, кто делит максимум; - оконная функция:
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC)в CTE, снаружи фильтрWHERE rnk = 1. Читается проще и не требует второго обращения к таблице; - коррелированный подзапрос:
WHERE e.salary = (SELECT MAX(s.salary) FROM employees s WHERE s.department_id = e.department_id). Короткий, и так задачу удобно записать на JPQL, где оконные функции есть не во всех реализациях.
Проговорите разницу функций ранжирования: ROW_NUMBER() оставит ровно одну строку на департамент и молча выбросит второго сотрудника с той же зарплатой, а RANK() и DENSE_RANK() вернут обоих. В условии сказано «всех сотрудников», значит, нужен RANK.
Про Java хватит пары фраз: в Spring Data такой запрос кладут в @Query с nativeQuery = true или пишут на JPQL через подзапрос, результат маппят на DTO или record, а не на сущность. На большой таблице выручает составной индекс (department_id, salary).
Где спотыкаются
Пишут SELECT name, department_id, MAX(salary) ... GROUP BY department_id. PostgreSQL на это вернёт ошибку, а MySQL с выключенным ONLY_FULL_GROUP_BY выполнит запрос и подставит имя случайного сотрудника из группы.
Берут ROW_NUMBER() или LIMIT 1 на департамент и теряют сотрудников с одинаковой максимальной зарплатой, хотя в условии прямо просят всех.
Джойнят подзапрос только по зарплате, забыв про департамент. Тогда в выборку попадает сотрудник, чья зарплата случайно совпала с максимумом чужого отдела.