leetcode解题小记 185. 部门工资前三高的所有员工

题目

  1. 部门工资前三高的所有员工
    SQL架构
    Employee 表包含所有员工信息,每个员工有其对应的工号 Id,姓名 Name,工资 Salary 和部门编号 DepartmentId 。

±—±------±-------±-------------+
| Id | Name | Salary | DepartmentId |
±—±------±-------±-------------+
| 1 | Joe | 85000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
| 5 | Janet | 69000 | 1 |
| 6 | Randy | 85000 | 1 |
| 7 | Will | 70000 | 1 |
±—±------±-------±-------------+
Department 表包含公司所有部门的信息。

±—±---------+
| Id | Name |
±—±---------+
| 1 | IT |
| 2 | Sales |
±—±---------+
编写一个 SQL 查询,找出每个部门获得前三高工资的所有员工。例如,根据上述给定的表,查询结果应返回:

±-----------±---------±-------+
| Department | Employee | Salary |
±-----------±---------±-------+
| IT | Max | 90000 |
| IT | Randy | 85000 |
| IT | Joe | 85000 |
| IT | Will | 70000 |
| Sales | Henry | 80000 |
| Sales | Sam | 60000 |
±-----------±---------±-------+
解释:

IT 部门中,Max 获得了最高的工资,Randy 和 Joe 都拿到了第二高的工资,Will 的工资排第三。销售部门(Sales)只有两名员工,Henry 的工资最高,Sam 的工资排第二。

思路

看到返回每个部门的条数不唯一的,首先就会想到分析函数类型中的窗口函数。
再根据示例的结果集,里面的“前三”的概念和我们通常说的不太一样。一般来说,类似成绩排名,如果第K名是有两人并列,那再往后的人应该是排K+2,而这里的结果是K+1。所以对应的窗口函数应该是dense_rank() (与之相对应的是,我们通常说的成绩排名这种搞法是rank(),当然,还有一种更为常见的是row_number(),这个函数是无视“并列”的情况的。)
这类函数的一般用法是

select xxx, dense_rank() over (partition by 分组字段 order by 组内排序字段) rank_index from ...

根据前面的分析,要按部门分组,故分组字段是Employee.DepartmentId,而取工资前三高的员工,排序字段就是Employee.Salary,注意要降序。最后用where条件筛选出题目意义的top3。

编程

两表间的关联直接用内连接即可,没什么特别。
因为最后结果列不包含排名,所以把思路一节里的筛选sql结果做一个子查询,外面包一层,选择显示的结果列,以及对rank_index限定<=3的条件。
PS:如果是写OLTP的系统,比如这段sql嵌在mybatis中,返回给java应用端映射成一个DTO,那这个子查询外面包一层就是多此一举。一般会视前端页面需要与否,在DTO转VO的时候,去掉这个rank_index字段而不是在sql里面处理。

代码

/* Write your PL/SQL query statement below */
select t2name as "Department", t1name as "Employee", Salary
from (select t1.Name as t1name, t2.Name as t2name, t1.Salary, dense_rank() over (partition by DepartmentId order by Salary desc) rank_index
from Employee t1 join Department  t2 on t1.DepartmentId = t2.ID
)t
where t.rank_index <= 3

扩展

如果不用分析函数写该怎么写?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值