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

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

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

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

题目主要信息:

  • 找到第二快和第二慢用时之差大于试卷时长的一半的试卷信息,按试卷ID降序排序
  • 试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间)
  • 试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)

问题拆分:

  • 找到每份试卷的ID、限制时间、发布时间以及每份试卷被完成的耗时、耗时降序排名和增序排名。这里的不用去重,也不用分组,因为每一份都要计算耗时:
    • 试卷信息与做题信息分布在两个表中,因此要将两个表以exam_id连接。知识点:join...on...
    • 只查询有提交时间的时间,筛掉没做完的试卷。知识点:where
    • 试卷ID、限制时间、发布时间直接获取,完成的耗时使用timestampdiff函数根据开始时间和提交时间计算分钟数差值。知识点:timestampdiff()
    • 利用分组聚合排名对每一种试卷的完成耗时分别进行增序排名和降序排名。知识点:row_number() over partition by
    • 查询出的表格记为table1
  • 根据上面筛选出来的信息查询每份试卷的限制时间、发布时间及第二快与第二慢的差值:
    • 每张不同的试卷都会有一个数据,因此以试卷ID作为分组。知识点:group by
    • 每组试卷的ID、限制时间、发布时间都可以由table1直接查询到。
    • 将每组试卷的完成时间累加,只有当最慢排名为2时才加正值,最快排名为2时加负值,其余情况加0.这样刚好是用时第二多减去用时第二少。 sum(case when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) as sub 知识点:sum()、case when...then...when...then...else...end
    • 查询出的结果记为table2
  • 最后从table2出筛选出大于等于限制时间一半的试卷ID,限制时间和发布时间
  • 输出按照试卷ID的降序排列。知识点:order by

代码:

select distinct exam_id, duration, release_time
from
    (select exam_id as exam_id, duration, release_time,
           sum(case when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) as sub
    from (
        select e_i.exam_id, duration, release_time,
        timestampdiff(minute, start_time, submit_time) as costtime,
        row_number() over(partition by e_r.exam_id order by timestampdiff(minute, start_time, submit_time) desc) rank1,
        row_number() over(partition by e_r.exam_id order by timestampdiff(minute, start_time, submit_time) asc) rank2
        from exam_record e_r join examination_info e_i
        on e_r.exam_id = e_i.exam_id
        where submit_time is not null 
    ) table1
    group by exam_id
) table2
where sub * 2 >= duration
order by exam_id desc
孤帆远影碧空尽 文章被收录于专栏

牛客网各类题单题解~

全部评论
sum(case when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) as sub 在一份试卷有三个记录时rank1=rank2=2,这不对吧
6 回复 分享
发布于 2022-06-27 19:53
第一行应该不需要加distinct了吧,后面已经有一个group by ,就不会再有重复的产生了
5 回复 分享
发布于 2022-04-01 13:07
【 timestampdiff(minute】这里用minute不严谨!
5 回复 分享
发布于 2021-10-24 20:26
最外层的嵌套可以省略,直接在where 后面 having sum(case when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) > ....
2 回复 分享
发布于 2022-08-20 16:31 湖北
如果只有两个人,那你赋值不就反了嘛
2 回复 分享
发布于 2022-03-26 19:38
这个摸鱼大师牛哇 专攻高阶sql "摸鱼"到这种境界 我也想 !!!
2 回复 分享
发布于 2022-03-10 14:20
如果某张试卷只有3条记录,第二快减第二慢应该为 0,这张试卷不满足条件,但是楼主的算法,第二快减第二慢为第二快记录的答题时长,这张试卷可能会被当做有效试卷。 可以使用(avg(costtime) - min(costtime)) * 2来算,这种方法可以计算3条记录的情况
1 回复 分享
发布于 2024-07-23 17:07 浙江
如果存在最快用时和最慢用时有多个时row_number()这个是不是不太严谨啊
1 回复 分享
发布于 2022-03-20 17:21
不用把case when的结果sum起来也可以通过,而且为什么group by后面只跟exam_id也可以通过呢
1 回复 分享
发布于 2022-02-16 16:20
实现用时第二多-用时第二少的逻辑是什么
1 回复 分享
发布于 2022-01-19 17:13
最后:where sub * 2 >= duration;也不是很严谨,题目是大于;
1 回复 分享
发布于 2021-12-10 00:02
" sum(case when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) as sub"这行计算用时真是神来之笔呀,还有作者同时计算出正序和倒序的排名,这点也很妙,总之妙极了,又涨知识了,需要指出的是计算时间差要换算成秒,分钟的话不精确
点赞 回复 分享
发布于 2023-09-07 18:01 北京
第二层直接having就可以哈
点赞 回复 分享
发布于 2023-06-24 22:37 日本
为什么 group by 后面只有一个exam_id也能不报错?我记得不是select除了聚合函数以外其它列都得跟group by 后面吗?
点赞 回复 分享
发布于 2022-08-23 13:48 上海
为什么我实例2会多出9001这一组
点赞 回复 分享
发布于 2022-07-15 13:42
select exam_id,duration,release_time from examination_info where exam_id in (select exam_id from (select t2.exam_id ,duration ,timestampdiff(second,start_time,submit_time) as tm ,row_number()over(partition by t2.exam_id order by timestampdiff(second,start_time,submit_time)) as rk ,count(*)over(partition by t2.exam_id ) as cnt from exam_record as t2 join examination_info as t1 using(exam_id) where score is not null) as t where rk=2 or rk=cnt-1 group by exam_id,duration having(max(tm)-min(tm)>duration*30) ) order by exam_id desc
点赞 回复 分享
发布于 2022-07-13 11:28
还有一个笨办法 SELECT exam_id,duration,release_time FROM (SELECT *, ROW_NUMBER() over(PARTITION BY exam_id ORDER BY `datediff`) as ranking1, ROW_NUMBER() over(PARTITION BY exam_id ORDER BY `datediff` DESC) as ranking2 FROM (SELECT e_r.*,(submit_time-start_time) as `datediff`,tag,difficulty,duration,release_time FROM exam_record as e_r LEFT JOIN examination_info as e_i ON e_r.exam_id=e_i.exam_id) as test WHERE `datediff` IS NOT NULL) AS e GROUP BY exam_id HAVING (sum(IF(ranking2=2,`datediff`,0))-sum(IF(ranking1=2,`datediff`,0)))>(duration/2)*60
点赞 回复 分享
发布于 2022-05-16 18:07
一直比较好奇为什么用rank过不了单杀用row_number能过
点赞 回复 分享
发布于 2022-05-04 10:45
#自己优化了一下,用秒代替分钟,添加了可能存在并列排名的情况 select distinct exam_id, duration, release_time from (select exam_id as exam_id, duration, release_time, sum(case when rank1 = rank2 then 0 when rank1 = 2 then costtime when rank2 = 2 then -costtime else 0 end) as sub from ( select e_i.exam_id, duration, release_time, timestampdiff(SECOND, start_time, submit_time) as costtime, rank() over(partition by e_r.exam_id order by timestampdiff(SECOND, start_time, submit_time) desc) rank1, rank() over(partition by e_r.exam_id order by timestampdiff(SECOND, start_time, submit_time) asc) rank2 from exam_record e_r join examination_info e_i on e_r.exam_id = e_i.exam_id where submit_time is not null ) table1 group by exam_id ) table2 where sub * 2 >= duration * 60 order by exam_id desc
点赞 回复 分享
发布于 2022-04-23 12:24
为什么需要第三个select呢,把第三个select后面的内容直接加到第二个select后为什么会出错呢
点赞 回复 分享
发布于 2022-04-06 16:01

相关推荐

评论
116
16
分享

创作者周榜

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