题解 | #第二快/慢用时之差大于试卷时长一半的试卷#

第二快/慢用时之差大于试卷时长一半的试卷

http://www.nowcoder.com/practice/b1e2864271c14b63b0df9fc08b559166

一、知识点总结


把有用的知识写在前面,以方便自个儿复习观看😊

1)排序窗口函数
  • rank() over() 1 2 2 4 4 6  (计数排名,跳过相同的几个,eg.没有3没有5)
  • row_number() over() 1 2 3 4 5 6 (赋予唯一排名)
  • dense_rank() over() 1 2 2 3 3 4 (不跳过排名,可以理解为对类别进行计数)

2)分类聚合函数
  • sum()...group by...

3)求时间差函数
  •  timestampdiff(时间格式,开始时间,结束时间)

Tips:解题小技巧
  • 一般涉及到同一类之间的对比求和等等操作的时候,常常会用到group by 函数来匹配聚类函数使用;
  • 如果涉及判断的操作,常常会用到条件语句只有1个判断可直接用if,如果大于1个判断选择用case when语句。


二、解题步骤拆分

1、题目解读

题目:找到第二快和第二慢用时之差大于试卷时长的一半的试卷信息,按试卷ID降序排序。

题目中隐藏的坑
坑1:第一快和第二慢:通过用户完成试卷的时间对比来定义快慢,首先需要求每张试卷的完成时间=(submit_time - start_time)命名为 time_diff
坑2:第二快和第二慢的用时之差=某科卷子的第二慢用时-该科卷子的第二快用时(这里我花了比较长的时间理解这句话的定义)

2、解题步骤拆分

STEP1:求各个试卷的用时之差,并进行正逆序排序
STEP2:求第二快和第二慢的用时之差,并和试卷规定时长(duration)进行对比
STEP3:试卷ID降序排序

三、步骤代码

1)求各个试卷的用时之差
timestampdiff(minute , start_time ,submit_time ) AS time_diff

2)进行正逆序排序
ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY time_diff DESC ) rk_desc -- 逆序 这里直接放time_diff 是为了便于理解,别名不能在同一层查询中直接使用

ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY time_diff ASC) -- 正序
正确代码:不用time_diff别名,直接用原函数timestampdiff(minute , start_time ,submit_time )
ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) DESC ) rk_desc -- 逆序 


ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) ASC ) rk_asc -- 正序
第一层子查询完整代码
SELECT a.exam_id,timestampdiff(minute,a.start_time,a.submit_time) time_diff ,b.duration,b.release_time,
	   ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) DESC ) rk_desc,
	   ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) ASC ) rk_asc
FROM exam_record a
LEFT JOIN examination_info b ON a.exam_id=b.exam_id
WHERE a.submit_time IS NOT NULL;

/* 该子查询命名为t1*/
rk_desc 对用时进行逆序排列,排名前用时长
rk_ace 对用时进行正序排列,排名前用时少


3)求第二快和第二慢的用时之差
代入场景理解下需求:exam_id=9001,当rk_desc=2时time_diff=50 ,当rk_asc=2时time_diff=11,两个time_diff的差为39
SUM(CASE WHEN rk_desc=2 THEN time_diff WHEN rk_asc=2 THEN -time_diff ELSE 0 END)

/*使用case when 进行赋值,取用时第二慢为正,第二快为负,其他未0,求和赋值后的9001试卷ID的所有用时*/

这里有两个判断所以选择用case when 语句。同时涉及到类数据之间的对比(exam_id)所以需要用到 group by 函数。
SELECT *,
	SUM(CASE WHEN rk_desc=2 THEN time_diff WHEN rk_asc=2 THEN -time_diff ELSE 0 END) sum_time
FROM t1
GROUP BY exam_id

/*该子查询命名为t2*/

4)将用时之差的两倍和试卷时长进行对比,选取需求字段,并按照试卷ID进行
降序排序
SELECT exam_id,duration,release_time
FROM t2
WHERE sum_time*2>=duration
ORDER BY exam_id DESC
;

四、完整代码组装

SELECT exam_id,duration,release_time
FROM(SELECT exam_id,duration,release_time,                      SUM(CASE WHEN rk_desc=2 THEN time_diff WHEN rk_asc=2 THEN -time_diff ELSE 0 END) sum_time      FROM (SELECT a.exam_id,timestampdiff(minute,a.start_time,a.submit_time) time_diff ,b.duration,b.release_time,                 ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) DESC ) rk_desc,                 ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) ASC ) rk_asc
            FROM exam_record a LEFT JOIN examination_info b ON a.exam_id=b.exam_id
            WHERE a.submit_time IS NOT NULL) t1     GROUP BY exam_id) t2
     
WHERE sum_time*2>=duration
ORDER BY exam_id DESC
;

SQL解题集 文章被收录于专栏

这是牛客SQL相关的解题集

全部评论
group by 查询不是只能查分组后的字段还有聚合函数吗,为什么楼主带了其他字段不会报错呢
6 回复 分享
发布于 2022-09-06 18:20 江苏
这个sum + case when 用法简直大气层
点赞 回复 分享
发布于 2022-08-24 17:09 江苏
太顶了,这个SUM+CASE when的配合,把我天顶盖都给震麻了
3 回复 分享
发布于 2022-07-29 12:57
这思路太清晰了!要练到什么程度才能跟楼主一样强大呀?!
2 回复 分享
发布于 2022-07-29 10:19
为什么我这边没办法运行,t2 那个 group by 里面的time_diff有多个变量,没办法直接group by exam_id吧
1 回复 分享
发布于 2022-03-31 19:57
sum不需要加绝对值吗,我在想要是只有两个数据的话,第二大的减去第二小的不就是负数,还有一个判断条件加等号是因为会向下取整吗
点赞 回复 分享
发布于 2023-06-23 19:54 广东
太强啦!讲得也很清楚
点赞 回复 分享
发布于 2023-04-30 17:48 江苏
点赞 回复 分享
发布于 2023-04-23 11:30 广东
厉害,确实厉害,那么长的条件
点赞 回复 分享
发布于 2023-03-02 16:26 江苏
点赞 回复 分享
发布于 2022-11-17 09:21 江苏
好聪明啊
点赞 回复 分享
发布于 2022-10-11 17:24 江西
非常感谢楼主的解答!!
点赞 回复 分享
发布于 2022-07-29 12:00
SELECT a.exam_id,timestampdiff(minute,a.start_time,a.submit_time) time_diff ,b.duration,b.release_time, ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) DESC ) rk_desc, ROW_NUMBER()OVER(PARTITION BY a.exam_id ORDER BY timestampdiff(minute,a.start_time,a.submit_time) ASC ) rk_asc FROM exam_record a LEFT JOIN examination_info b ON a.exam_id=b.exam_id WHERE a.submit_time IS NOT NULL; /* 该子查询命名为t1*/ 在最内层子查询使用窗口函数后,排序没有用group by,最后得到的排序结果我可以理解。但接着其外层用了Group by,请问这用了group by后是咋排序呢?是exam_id为9001的1234、id为9002的1234这样排下来,还是咋样?不是很理解为什么要用group by
点赞 回复 分享
发布于 2022-05-29 19:55
为什么不用time_diff别名,直接用原函数timestampdiff(minute , start_time ,submit_time )呀,窗口函数order by这里我用了别名就报错了
点赞 回复 分享
发布于 2022-05-07 15:08

相关推荐

09-18 14:40
门头沟学院 Java
多益网络为什么一面完还是等待面试啊,这是过了还是挂了啊
哆嗐网络受缢人:多在小红书 知乎之类的平台看看大家的评价,看看公司是如何对待应届生和老员工的吧。或者看看我的主页😭
我的秋招日记
点赞 评论 收藏
分享
08-10 12:43
临沂大学 Java
等闲_:1,换一个模版,这个模版没有人会看的 2,项目太烂大街了,也太简单了,找AI优化一下描述,项目可以烂大街,但是简历不能烂大街,或者找项目换一下 3,如果没什么奖的话,把学校放到下面,添加一个个人描述,简单些,让简历丰富一些 4,改完之后海投试试,但是我真的很建议别走java了,可以试试前端
点赞 评论 收藏
分享
评论
107
20
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务