Stanleyrr
Stanleyrr

Reputation: 875

Get top salary by department without using any subquery

Let's say we have 2 database tables - emp and dept, which consists of the following columns

emp: empid, deptid, salary

dept: deptid, deptname

The deptid column in emp can be joined with deptid column in dept column. Note that some departments don't have any employee. For those cases, the deptid in dept table won't exist in emp table. We need to find top salary in each department. For departments that don't have any employee, we need to assign them the highest salary from emp table. One requirement is that we can NOT use subquery, but CTE (common table expression) is allowed.

Below is the query I built:

with cte as 
(Select d.deptid, e.salary, row_number() over (partition by d.deptid order by e.salary desc) as rnk,
row_number() over(order by e.salary desc) as salary_rank    
from emp e 
join dept d on e.deptid = dept.deptid),

top_salary as 
(Select d.deptid, e.salary 
from emp e 
join dept d on e.deptid = dept.deptid
order by e.salary desc
limit 1)


(Select d.deptid, cte.salary 
from cte 
join dept d on d.deptid = cte.deptid
where cte.rnk = 1) as t1

UNION 

(Select d.deptid, ts.salary  
from dept d 
left join cte on cte.deptid = d.deptid 
left join top_salary ts on ts.deptid = cte.deptid 
where cte.salary is null
)

But I am not sure if I did it correctly, especially in cases where the departments don't have any employees. I am also not sure if the 2 queries I wrote surrounding the UNION clause are considered subqueries. If they are indeed subqueries, then is there a way I can rewrite that query without using any subquery?

Upvotes: 0

Views: 146

Answers (1)

Gordon Linoff
Gordon Linoff

Reputation: 1269883

We need to find top salary in each department. For departments that don't have any employee, we need to assign them the highest salary from emp table.

Your attempt seems overly complicated:

with edmax as (
      select e.deptid, max(e.salary) as max_salary
      from emp
      group by e.deptid
     ),
     emax as (
      select max(e.salary) as max_salary
     )
select d.*, max(edmax.max_salary, emax.max_salary) as max_salary
from dept d left join
     edmax
     on d.deptid = edmax.deptid cross join
     emax;

The basic idea is to calculate the maximum salary for each department and then "default" to the overall maximum.

By the way, you could do this only with joins:

select d.deptid, d.name,
       coalesce(max(de.salary), max(d.salary))
from emp e cross join
     dept d left join
     dept de
     on de.deptid = e.deptid
group by d.deptid, d.name;

I don't recommend this approach but you might want to understand it.

Upvotes: 1

Related Questions