牛客网SQL进阶137:第二快/慢用时之差大于试卷时长一半的试卷

官网链接:

第二快慢用时之差大于试卷时长一半的试卷_牛客题霸_牛客网现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别,。题目来自【牛客题霸】https://www.nowcoder.com/practice/b1e2864271c14b63b0df9fc08b559166?tpId=240

0 问题描述

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

1 数据准备

sql 复制代码
drop table if exists examination_info,exam_record;
CREATE TABLE examination_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    exam_id int UNIQUE NOT NULL COMMENT '试卷ID',
    tag varchar(32) COMMENT '类别标签',
    difficulty varchar(8) COMMENT '难度',
    duration int NOT NULL COMMENT '时长',
    release_time datetime COMMENT '发布时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE exam_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    exam_id int NOT NULL COMMENT '试卷ID',
    start_time datetime NOT NULL COMMENT '开始时间',
    submit_time datetime COMMENT '提交时间',
    score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
  (9001, 'SQL', 'hard', 60, '2021-09-01 06:00:00'),
  (9002, 'C++', 'hard', 60, '2021-09-01 06:00:00'),
  (9003, '算法', 'medium', 80, '2021-09-01 10:00:00');


INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-09-01 09:01:01', '2021-09-01 09:51:01', 78),
(1001, 9002, '2021-09-01 09:01:01', '2021-09-01 09:31:00', 81),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 81),
(1003, 9001, '2021-09-01 19:01:01', '2021-09-01 19:59:01', 86),
(1003, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:51', 89),
(1004, 9002, '2021-09-01 19:01:01', '2021-09-01 19:30:01', 85),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:02', 85),
(1006, 9001, '2021-09-07 10:01:01', '2021-09-07 10:12:01', 84),
(1003, 9001, '2021-09-08 12:01:01', '2021-09-08 12:11:01', 40),
(1003, 9002, '2021-09-01 14:01:01', null, null),
(1005, 9001, '2021-09-01 14:01:01', null, null),
(1003, 9003, '2021-09-08 15:01:01', null, null);

2 数据分析

完整的代码如下:

sql 复制代码
select distinct exam_id,
                duration,
                release_time
from(select exam_id,
            duration,
            release_time,
            sum(case when rn1 =2 then difftime
                 when rn2 =2 then -difftime
                 else 0
                 end ) as sub
    from(select
               exam_id,
               duration,
               release_time,
               difftime,
               row_number() over(partition  by exam_id order by difftime desc ) as rn1,
               row_number() over(partition  by exam_id order by difftime ) as rn2
        from (select
                   er.exam_id,
                   ei.duration,
                   ei.release_time,
                   timestampdiff(minute,er.start_time,er.submit_time) as difftime
              from exam_record er  join examination_info ei
              on  er.exam_id = ei.exam_id
              where submit_time is not null)tmp1
         )tmp2
    group by exam_id
    )tmp3
  where sub * 2 >= duration
   order by exam_id desc;

上述的解题步骤拆分

step1:求出各试卷的用时之差,并进行正序、逆序排序

step2:求出第二快和第二慢的用时之差,并和试卷规定时长(duration)进行比对

step3:试卷ID降序排序

步骤代码

step1:

sql 复制代码
select
      exam_id,
      duration,
      release_time,
      difftime,
      --进行正序、逆序排序
      row_number() over(partition  by exam_id order by difftime desc ) as rn1,
      row_number() over(partition  by exam_id order by difftime ) as rn2
from (select
           er.exam_id,
           ei.duration,
           ei.release_time,
           --step1:求出各试卷的用时之差timestampdiff,并进行正序、逆序排序
           timestampdiff(minute,er.start_time,er.submit_time) as difftime
      from exam_record er  join examination_info ei
      on  er.exam_id = ei.exam_id
      where submit_time is not null)tmp1;

step2: 使用 case when进行赋值, 当rn1 =2 时,代表是第二快的difftime(取正值);当rn2 =2 时,代表是第二慢的difftime(需要取负值); 外层再嵌套sum聚合函数,即得到第二快和第二慢的用时之差sub

sql 复制代码
select exam_id,
       duration,
       release_time,
        sum(case when rn1 =2 then difftime
                 when rn2 =2 then -difftime
                 else 0
                 end ) as sub
from(select
             exam_id,
             duration,
             release_time,
             difftime,
             row_number() over(partition  by exam_id order by difftime desc ) as rn1,
             row_number() over(partition  by exam_id order by difftime ) as rn2
    from (select
                er.exam_id,
                ei.duration,
                ei.release_time,
                timestampdiff(minute,er.start_time,er.submit_time) as difftime
           from exam_record er  join examination_info ei
            on  er.exam_id = ei.exam_id
             where submit_time is not null)tmp1
        )tmp2
 group by exam_id;

**step3:**sub和试卷规定时长(duration)进行比对,要求:sub * 2 >= duration

sql 复制代码
select distinct exam_id,
                duration,
                release_time
from(select exam_id,
            duration,
            release_time,
            sum(case when rn1 =2 then difftime
                 when rn2 =2 then -difftime
                 else 0
                 end ) as sub
    from(select
               exam_id,
               duration,
               release_time,
               difftime,
               row_number() over(partition  by exam_id order by difftime desc ) as rn1,
               row_number() over(partition  by exam_id order by difftime ) as rn2
        from (select
                   er.exam_id,
                   ei.duration,
                   ei.release_time,
                   timestampdiff(minute,er.start_time,er.submit_time) as difftime
              from exam_record er  join examination_info ei
              on  er.exam_id = ei.exam_id
              where submit_time is not null)tmp1
         )tmp2
    group by exam_id
    )tmp3
  where sub * 2 >= duration
   order by exam_id desc;

3 小结

上述案例用到的知识点:

(1)timestampdiff函数

timestampdiff: MySQL 中用来计算两个日期或时间之间的差值的函数;

语法:timestampdiff(unit, start_date, end_date)

参数说明:

unit: 差值的单位,可以是second(秒)、minute(分)、hour(小时)、day(天)、week(周)、month(月)、quarter(季度)或 year(年)。

start_date:表示时间段的起始时间

end_date:表示时间段的结束时间

(2)row_number() over(partition by ..order by ..desc)窗口函数

(3)sum +case when :条件+聚合

相关推荐
HackTwoHub7 分钟前
AI大模型网关存在SQL注入、附 POC 复现、影响版本LiteLLM 1.81.16~1.83.7(CVE-2026-42208)
数据库·人工智能·sql·网络安全·系统安全·网络攻击模型·安全架构
l1t13 分钟前
DeepSeek总结的DuckLake构建基于 SQL 原生表格式的下一代数据湖仓
数据库·sql
KmSH8umpK21 分钟前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第八篇
数据库·redis·分布式
TDengine (老段)1 小时前
从施工监测到运营预警,桥科院用 TDengine 提升桥梁数据管理能力
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
宁波鹿语心理1 小时前
无条件的在场:一项极简亲子依恋修复练习的机制分析与实证观察
大数据
S1998_1997111609•X2 小时前
论mysql国盾shell-sfa犯罪行为集团下的分项工程及反向注入原理尐深度纳米算法下的鐌檵鄐鉎行为
网络·数据库·网络协议·百度·开闭原则
KmSH8umpK3 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第七篇
数据库·redis·分布式
yaodong5184 小时前
不会Python也能数据分析:Gemini 3.1 Pro解决办公问题的SQL自动生成
python·sql·数据分析
BU摆烂会噶4 小时前
【LangGraph】持久化实现的三大能力——时间旅行
数据库·人工智能·python·postgresql·langchain
l1t5 小时前
DeepSeek总结的DuckLake 入门
数据库