SQL今日一题(11):窗口函数

本文是SQL每日一题的第11题,讲解如何获取部门中当前薪水最高的员工信息。通过三种方法解析,涉及max函数、分组原则及窗口函数row_number()的使用。通过对数据表dept_emp和salaries的连接与操作,揭示了在不同数据库环境中处理分组和排序的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是SQL今日一题的第11篇文章

题目描述

获取所有部门中当前(dept_emp.to_date = '9999-01-01')员工当前(salaries.to_date='9999-01-01')薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary

这题用到dept_emp表和salaries表,以emp_no为公共字段

dept_emp表

dept_emp表


salaries表

salaries表

方法1

select d.dept_no,d.emp_no,max(s.salary) as salary from  dept_emp as d,salaries as s
where d.emp_no = s.emp_no and d.to_date = '9999-01-01' and s.to_date = '9999-01-01'
group by d.dept_no,d.emp_no

通常的想法就是这样写了,max函数取最大值再对d.dept_no和d.emp_no分组,结果如下图所示,但其实这样取出来是不符合结果的,因为题目要求一个部门只有一个薪水的最大值,但因为我们对emp_no也分组了,所以会取出来一个部门下不同员工的salary。

 

 

方法2

select r.dept_no,r.emp_no,max(r.salary) from (
select d.dept_no,d.emp_no,s.salary from dept_emp d,salaries s
where d.emp_no=s.emp_no
and d.to_date='9999-01-01' 
and s.to_date='9999-01-01'
order by s.salary desc
)as r
group by r.dept_no
order by r.dept_no asc

这道题网上有很多种解答方法,这种解法是牛客网上讨论最多的一种。

1、首先将两个表连接起来按salary降序,where子句给出限定条件“当前”日期和公共字段的连接,将连接后的表命名为r表

2、再将r表按照dept_no分组,并从中取出最大的salary

这是只对dept_no分组,但细琢磨这是不对的,因为按照语法,group by 后要跟select以后聚合函数前的所有字段,也就是说select dept_no,emp_no了以后,group by 就必须包含dept_no和emp_no。

有的数据库可以只对dept_no分组,但返回的emp_no是默认取第一条,这里第一条不一定是最大的salary对应的那条,因此要先对salary降序排列,而根据语法,order by 要写在group by的后面,所以用了子查询。

而有的数据库group by会很严格的报错,所以要如何绕过emp_no分组呢?

方法3

select rank.dept_no,rank.emp_no,rank.salary from
(select d.dept_no,d.emp_no,s.salary,
 ROW_NUMBER() over(partition by d.dept_no order by s.salary desc) as nums 
from dept_emp d,salaries s where d.emp_no=s.emp_no 
 and d.to_date='9999-01-01' and s.to_date='9999-01-01') rank
where rank.nums = 1

其实对方法1中的结果我们只要再增加一列排序就可以了啊,对每一个分组降序排列,取每个排序为1的不就符合题目要求了吗,实现的方法就要用到窗口函数里的row_number() over()了。

 

1、首先将dept_emp和salaries两个表以公共字段emp_no连接起来,并用where子句限制“当前”条件

2、同时加入row_number() over(partition by d.dept_no order by s.salary)语句,意思是按照dept_no分组,在每一个dept_no的分组内按照salary降序排列,排序之后,对每一个分组内的多行数据,标记上序号,序号从1开始,依次递增,同时也给序号赋值为nums

3、进行开窗操作后,再进行一次select+where的操作,来选出需要的数据,即nums = 1的记录。

 

以上3种方法均能通过牛客网的练习,但能通过不代表就是对的,这道题目很值得思考,尤其是对group by和窗口函数掌握不深入的小伙伴来说,看一眼就过了,以为自己明白了,但其实还差得多,希望大家好好思考。

知识点

max函数

  • 返回指定列中的最大值
  • 要指定列名,如max(column)

row_number

  • 语法:row_number() over(partition by column1,column2 order by column3) as column4
  • 按照column1,column2分组,对每个组内按照column3排序,并将排序的序号命名为column4
  • 赋予唯一的连续位次,如有相同的3条记录排名为1时,结果记为1,2,3

猜你喜欢:
数据分析应关注AARRR模型的哪些指标

泰坦尼克号数据分析

深入浅出数据分析

《吊打分析师》实战—我要租个好房

为什么要学统计学:赤裸裸的统计学

成为数据分析师的第三年,我写了10W字

@ 作者:可乐
@ 公众号/知乎专栏/头条/简书:可乐的数据分析之路
@加个人微信:data_cola,备注:进群,拉你入 可乐的数据分析群 和各行各业的小伙伴交流探讨数据分析相关内容

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的可乐!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值