Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Employees with largest salary in department

Tags:

sql

postgresql

I found a couple of SQL tasks on Hacker News today, however I am stuck on solving the second task in Postgres, which I'll describe here:

You have the following, simple table structure:

enter image description here

List the employees who have the biggest salary in their respective departments.

I set up an SQL Fiddle here for you to play with. It should return Terry Robinson, Laura White. Along with their names it should have their salary and department name.

Furthermore, I'd be curious to know of a query which would return Terry Robinsons (maximum salary from the Sales department) and Laura White (maximum salary in the Marketing department) and an empty row for the IT department, with null as the employee; explicitly stating that there are no employees (thus nobody with the highest salary) in that department.

like image 202
skinkelynet Avatar asked Dec 27 '22 03:12

skinkelynet


1 Answers

Return one employee with the highest salary per dept.

Use DISTINCT ON for a much simpler and faster query that does all you are asking for:

SELECT DISTINCT ON (d.id)
       d.id AS department_id, d.name AS department
      ,e.id AS employee_id, e.name AS employee, e.salary
FROM   departments d
LEFT   JOIN employees e ON e.department_id = d.id
ORDER  BY d.id, e.salary DESC;

->SQLfiddle (for Postgres).

Also note the LEFT [OUTER] JOIN that keeps departments with no employees in the result.

This picks only one employee per department. If there are multiple sharing the highest salary, you can add more ORDER BY items to pick one in particular. Else, an arbitrary one is picked from peers.
If there are no employees, the department is still listed, with NULL values for employee columns.

You can simply add any columns you need in the SELECT list.

Find a detailed explanation, links and a benchmark for the technique in this related answer:
Select first row in each GROUP BY group?

Aside: It is an anti-pattern to use non-descriptive column names like name or id. Should be employee_id, employee etc.

Return all employees with the highest salary per dept.

Use the window function rank() (like @Scotch already posted, just simpler and faster):

SELECT d.name AS department, e.employee, e.salary
FROM   departments d
LEFT   JOIN (
   SELECT name AS employee, salary, department_id 
         ,rank() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk
   FROM   employees e
   ) e ON e.department_id = d.department_id AND e.rnk = 1;

Same result as with the above query with your example (which has no ties), just a bit slower.

like image 182
Erwin Brandstetter Avatar answered Jan 18 '23 09:01

Erwin Brandstetter