drop table employees
Create table employees(Id int,Company varchar(2),salary int,);
insert into employees values(1,'A',2341);
insert into employees values(2,'A',341);
insert into employees values(3,'A',15);
insert into employees values(4,'A',15314);
insert into employees values(5,'A',451);
insert into employees values(6,'A',513);
insert into employees values(7,'B',15);
insert into employees values(8,'B',13);
insert into employees values(9,'B',1154);
insert into employees values(10,'B',1345);
insert into employees values(11,'B',1221);
insert into employees values(12,'B',234);
insert into employees values(13,'C',2345);
insert into employees values(14,'C',2645);
insert into employees values(15,'C',2645);
insert into employees values(16,'C',2652);
insert into employees values(17,'C',65);
select * from employees
The Employee
table holds all employees. The employee table has three columns: Employee Id, Company Name, and Salary.
+-----+------------+--------+
|Id | Company | Salary |
+-----+------------+--------+
|1 | A | 2341 |
|2 | A | 341 |
|3 | A | 15 |
|4 | A | 15314 |
|5 | A | 451 |
|6 | A | 513 |
|7 | B | 15 |
|8 | B | 13 |
|9 | B | 1154 |
|10 | B | 1345 |
|11 | B | 1221 |
|12 | B | 234 |
|13 | C | 2345 |
|14 | C | 2645 |
|15 | C | 2645 |
|16 | C | 2652 |
|17 | C | 65 |
+-----+------------+--------+
Write a SQL query to find the median salary of each company. Bonus points if you can solve it without using any built-in SQL functions.
+-----+------------+--------+
|Id | Company | Salary |
+-----+------------+--------+
|5 | A | 451 |
|6 | A | 513 |
|12 | B | 234 |
|9 | B | 1154 |
|14 | C | 2645 |
+-----+------------+--------+
Solution:
with cte as(
select Id,Company,salary
,ROW_NUMBER() over(partition by Company order by salary) as rnk
,count(*) over(partition by Company) as cnt
from employees
)select Id,Company,salary from cte
where rnk in (CEILING(cnt/2.0),cnt/2+1)
with cte as(
select Id,Company,salary,
dense_RANK() over(partition by Company order by salary desc) as rnk
from employees
),
cte2 as(select Company,count(*) as cnt
from employees
group by Company)
select c1.Id,c1.Company,c1.Salary,c1.rnk,c2.cnt
from cte c1 join cte2 c2 on c1.Company=c2.company
where rnk in (ceiling(cnt/2.0),cnt/2+1)
Two CTE makes more clear from readibility perspective