题目类型:MySql

力扣上的一道算法题,也是看了评论区的大神解析后才知晓怎么做。可以拓展为分组查询前几的数据。

问题:

有两张表,一张员工表(Employee),一张部门表(Department),查各个部门前三的薪资的部门名字+员工信息

自己的想法:

①先按照各个部门进行分组,再在各个部门中按照薪水进行排序,最后再找出各个部门中薪资排名前三的数据
②实现

select Department, Employee, Salary
from(
    select d.Name Department, e.Name Employee, e.Salary as Salary,
        dense_rank() over ( partition by DepartmentId order by Salary desc) r
    from Employee as e, Department as d where d.Id = e.DepartmentId) t 
where r<=3;

③后面我也用其他的函数试了一下,发现(以上面sql语句进行测试)

/**
*	排序函数,它是在每一条数据前加上一个序号,
*	缺点:若是出现相同的数据的情况就会出现问题,因为只获取到前三条数据
*	假设薪资前三的数据是 9000(1) 8500(2) 8500(3) 7000(4) 只获取了前三条
*/
row_number()  
/**
*	rank的排序方式是如果出现薪资相同的情况下,它们排序数字是一样的
*	假设薪资前三的数据是 9000(1) 8500(2) 8500(2) 7000(4) 
*	因为rank是跳跃式的排序方式,所以还是会出现问题
*/
rank()
/**
*	dense_rank的排序方式和rank差不多,区别就是它的排序是连续性的
*	假设薪资前三的数据是 9000(1) 8500(2) 8500(2) 7000(3) 
*/
dense_rank()
/**
*	这个函数可以理解成分区或者分组,但是我感觉好像有点像随机的
*	NTILE(1) 将查询到的数据分为同一个区 1
*	NTILE(2) 将查询到的数据分为两个区 1 2
*/
NTILE()

分享:

分享一个大佬的做法:
①找出各个部门的前三个,也就是说部门id一样,然后薪资大于某一个薪资的只有两个,加上这个“某一个”就是三个。先查找出这三个薪资的id集。此处有一个关键点就是去重,而且去重是得去掉薪水重复的,但是其实id是没有被去掉的。

select e1.Id from Employee e1 left join Employee e2 on e1.DepartmentId = e2.DepartmentId and e1.Salary<e2.Salary group by e1.Id having count(distinct e2.Salary)<=2

②将①中查询获取的id集进行查询即可,此处记得对比department的id需要在部门表中存在,因为测试用例中可能存在部门表中并没有部门信息存在,导致报错。其中根据部门id进行升序,按照薪水进行降序

select d.Name Department,e.Name Employee,e.Salary Salary from Employee e left join Department d on e.DepartmentId = d.Id  where e.Id in 
(①)
and e.DepartmentId in (select Id from Department) order by d.Id asc,e.Salary desc