当前位置: 首页 > news >正文

如何在使用窗口函数的时候使用groupby

如何在使用窗口函数的时候使用groupby

先说结论:groupby的执行先于窗口函数,也就是说对于非groupby字段而言,聚合函数先于窗口函数执行。过去写的sql很少在使用group by操作的同时使用窗口函数,主要是这种情况少见且在写sql时会刻意规避同时使用的情况。但是,同时使用两者在解决部分查询问题时能提供很大的遍历。今天回顾过去写的sql时发现这么一道必须同时使用窗口函数和groupby的题目。牛客网sql进阶中第五小结SQL1。

题目如下

现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):

idexam_idtagdifficultydurationrelease_time
19001SQLhard602021-09-01 06:00:00
29002SQLhard602021-09-01 06:00:00
39003算法medium802021-09-01 10:00:00

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):

iduidexam_idstart_timesubmit_timescore
1100190012021-09-01 09:01:012021-09-01 09:31:0078
2100290012021-09-01 09:01:012021-09-01 09:31:0081
3100290022021-09-01 12:01:012021-09-01 12:31:0181
4100390012021-09-01 19:01:012021-09-01 19:40:0186
5100390022021-09-01 12:01:012021-09-01 12:31:5189
6100490012021-09-01 19:01:012021-09-01 19:30:0185
7100590032021-09-01 12:01:012021-09-01 12:31:0285
8100690032021-09-07 10:01:012021-09-07 10:21:0184
9100390032021-09-08 12:01:012021-09-08 12:11:0140
10100390022021-09-01 14:01:01(NULL)(NULL)

找到每类试卷得分的前3名,如果两人最大分数相同,选择最小分数大者,如果还相同,选择uid大者。由示例数据结果输出如下:

tiduidranking
SQL10031
SQL10042
SQL10023
算法10051
算法10062
算法10033

解决方法

这道题其实逻辑很简单:需要先求出不同种类试卷中不同用户得分的最大值和最小值:

select exam_record.uid,examination_info.tag,
max(max(exam_record.score)) over(partition by examination_info.tag,exam_record.uid) max_score, 
min(min(exam_record.score)) over(partition by examination_info.tag,exam_record.uid) min_score
from exam_record
inner join examination_info
on exam_record.exam_id = examination_info.exam_id
where exam_record.score is not null
group by exam_record.uid,examination_info.tag

此时你会发现这里必须同时使用group by和窗口函数,那么问题来了,是group by先执行还是窗口函数先执行呢?答案是groupby先执行。上面的sql中max(exam_record.score)将先执行一次,再由max(max(exam_record.score))执行窗口函数响应的操作。其实这不是最优写法,最优写法如下:

select exam_record.uid,examination_info.tag,
row_number() over (partition by tag order by tag, max(score) desc, min(score) desc, exam_record.uid desc) as ranking
from exam_record  join examination_info 
on exam_record.exam_id = examination_info.exam_id
group by examination_info.tag, exam_record.uid

这种写法更简洁,但不熟悉窗口函数的同学可能看到会很晕,然后当自己同时使用窗口函数和groupby时一写就报错。事实上,只需要在写sql时注意groupby后面没有出现的字段在select中使用聚合函数进行求解。聚合函数会先于窗口函数执行。

本题最终答案如下:

解法一(本人自己想的解法,主要是一开始没有掌握好聚合函数和窗口函数运行的时机):

select t2.tag,t2.uid,t2.trank  from (
select  t1.uid,t1.tag,row_number() over(partition by t1.tag order by t1.max_score desc ,t1.min_score desc,t1.uid desc) trank from(
select exam_record.uid,examination_info.tag,max(max(exam_record.score)) over(partition by examination_info.tag,exam_record.uid) max_score, 
min(min(exam_record.score)) over(partition by examination_info.tag,exam_record.uid) min_scorefrom exam_record
inner join examination_info
on exam_record.exam_id = examination_info.exam_id
where exam_record.score is not null
group by exam_record.uid,examination_info.tag
) t1
)t2
where t2.trank <=3;

解法二:

select tag, uid, ranking
from(select tag, e_r.uid,row_number() over (partition by tag order by tag, max(score) desc, min(score) desc, e_r.uid desc) as rankingfrom exam_record e_r join examination_info e_ion e_r.exam_id = e_i.exam_idgroup by tag, e_r.uid
)ranktable
where ranking <= 3

http://www.mrgr.cn/news/23907.html

相关文章:

  • 02 Docker基本管理
  • 数据结构 | 深入理解顺序表与链表
  • Python 数学建模——方差分析
  • Java+vue的医药进出口交易系统(源码+数据库+文档)
  • Java中的常用类及包装类
  • Camera2 预览旋转方向、拍照、录像成像旋转
  • JAVA今日分享-30道常见的Java+MyBatis面试题
  • Hive SQL查询汇总分析
  • 数据库C语言删除修改和输出
  • NLP基础及其代码-tokenizer
  • 数字的补数
  • 多元素枚举问题
  • 数据结构 Java DS——分享部分链表题目 (2)
  • 智能工厂程序设计 之-2 (Substrate) :三个世界--“存在的意义”-“‘我’的价值的实现” 之2
  • U9的可用量管制功能失效了
  • 【03】深度学习——神经网络原理 | 多层感知机 | 前向传播和反向传播 | 多层感知机代码实现 | 回归问题、分类问题 | 多分类问题代码实现
  • day3 QT
  • 【Linux进程详解】进程地址空间
  • 【算法专题--回文】最长回文子串 -- 高频面试题(图文详解,小白一看就懂!!)
  • C:题目介绍