牛客刷题-SQL进阶挑战大总结(细节狂魔)


哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10年DBA工作经验
一位上进心十足的【大数据领域博主】!
中国DBA联盟(ACDU)成员,目前从事DBA及程序编程
擅长主流数据Oracle、MySQL、PG 运维开发,备份恢复,安装迁移,性能优化、故障应急处理等。
✨ 如果有对【数据库】感兴趣的【小可爱】,欢迎关注【IT邦德】
❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️

文章目录

  • 前言
    • 1.增删改操作
      • 1.1 插入记录
        • SQL1 插入记录(一)
        • SQL2 插入记录(二)
        • SQL3 插入记录(三)
      • 1.2 更新记录
        • SQL4 更新记录(一)
        • SQL5 更新记录(二)
      • 1.3 删除记录
        • SQL6 删除记录(一)
        • SQL7 删除记录(二)
        • SQL8 删除记录(三)
    • 2.表与索引操作
      • 2.1 表的创建、修改与删除
        • SQL9 创建一张新表
        • SQL10 修改表
        • SQL11 删除表
      • 2.2 索引的创建、删除
        • SQL12 创建索引
        • SQL13 删除索引
    • 3.聚合分组查询
      • 3.1 聚合函数
        • SQL14 SQL类别高难度试卷得分的截断平均值
        • SQL15 统计作答次数
        • SQL16 得分不小于平均分的最低分
      • 3.2 分组查询
        • SQL17 平均活跃天数和月活人数
        • SQL18 月总刷题数和日均刷题数
        • SQL19 未完成试卷数大于1的有效用户
    • 4.多表查询
      • 4.1 嵌套子查询
        • SQL20 月均完成试卷数不小于3的用户爱作答的类别
        • SQL21 试卷发布当天作答人数和平均分
        • SQL22 作答试卷得分大于过80的人的用户等级分布
      • 4.2 合并查询
        • SQL23 每个题目和每份试卷被作答的人数和次数
        • SQL24 分别满足两个活动的人
      • 4.3 连接查询
        • SQL25 满足条件的用户的试卷完成数和题目练习数
        • SQL26 每个6/7级用户活跃情况
    • 5.窗口函数
      • 5.1 专用窗口函数
        • SQL27 每类试卷得分前3名
        • SQL28 第二快/慢用时之差大于试卷时长一半的试卷
        • SQL29 连续两次作答试卷的最大时间窗
        • SQL30 近三个月未完成试卷数为0的用户完成情况
        • SQL31 未完成率较高的50%用户近三个月答卷情况
        • SQL32 试卷完成数同比2020年的增长率及排名变化
      • 5.2 聚合窗口函数
        • SQL33 对试卷得分做min-max归一化
        • SQL34 每份试卷每月作答数和截止当月的作答总数
        • SQL35 每月及截止当月的答题情况

前言

SQL每个人都要用,但是用来衡量产出的并不是SQL本身,你需要用这个工具,去创造其它的价值。

1.增删改操作

1.1 插入记录

在这里插入图片描述

SQL1 插入记录(一)

表exam_record结构
在这里插入图片描述

 题目描述
牛客后台会记录每个用户的试卷作答记录到exam_record表,现在有两个用户的作答记录详情如下:
用户1001202191日晚上101112秒开始作答试卷9001,并在50分钟后提交,得了90分;
用户1002202194日上午712秒开始作答试卷9002,并在10分钟后退出了平台。
试卷作答记录表exam_record中,表已建好,其结构如下,请用一条语句将这两条记录插入表中。

该题最后会通过执行SELECT uid, exam_id, start_time, submit_time, score FROM exam_record;
来对比结果

 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
TRUNCATE exam_record;


 答案
insert INTO exam_record 
values(null,1001,9001,'2021-09-01 22:11:12','2021-09-01 23:01:12',90),
(null,1002,9002,'2021-09-04 07:01:02',null,null);

在这里插入图片描述

SQL2 插入记录(二)

表exam_record结构
在这里插入图片描述

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,
由于数据越来越多,维护难度越来越大,需要对数据表内容做精简,历史数据做备份。

我们已经创建了一张新表exam_record_before_2021用来备份2021年之前的试题作答记录,
结构和exam_record表一致,请将2021年之前的已完成了的试题作答纪录导入到该表。
后台会通过执行"SELECT * FROM exam_record_before_2021;"语句来对比结果


 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
CREATE TABLE IF NOT EXISTS exam_record_before_2021 (
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;
TRUNCATE exam_record;
TRUNCATE exam_record_before_2021;
INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-01 09:00:01', null, null),
(1001, 9002, '2020-01-02 09:01:01', '2020-01-02 09:21:01', 70),
(1001, 9002, '2020-09-02 09:00:01', null, null),
(1002, 9001, '2021-05-02 10:01:01', '2021-05-02 10:30:01', 81),
(1002, 9002, '2021-09-02 12:01:01', null, null);


 答案
INSERT INTO exam_record_before_2021
SELECT NULL,uid, exam_id, start_time, submit_time, score
FROM exam_record
WHERE submit_time < '2021-01-01 00:00:00';

在这里插入图片描述

SQL3 插入记录(三)

试题信息表examination_info结构
在这里插入图片描述

 题目描述
现在有一套ID为9003的高难度SQL试卷,时长为一个半小时,
请你将 2021-01-01 00:00:00 作为发布时间插入到试题信息表examination_info,不管该ID试卷是否存在,都要插入成功,请尝试插入它。
后台会通过执行 SELECT exam_id,tag,difficulty,duration,release_time FROM examination_info 语句来对比结果。

 建表语句
drop table if EXISTS examination_info;
CREATE TABLE IF NOT EXISTS 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_bin;
TRUNCATE examination_info;
INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
(9001, 'SQL', 'hard', 60, '2020-01-01 10:00:00'),
(9002, '算法', 'easy', 60, '2020-01-01 10:00:00'),
(9003, 'SQL', 'medium', 60, '2020-01-02 10:00:00'),
(9004, '算法', 'hard', 80, '2020-01-01 10:00:00');

 答案
replace into examination_info
(id,exam_id,tag,difficulty,duration,release_time)
values(null,9003,'SQL','hard',90,'2021-01-01 00:00:00');

在这里插入图片描述

1.2 更新记录

SQL4 更新记录(一)

现有一张试卷信息表examination_info,表结构如下图所示:
在这里插入图片描述

 题目描述
请把examination_info表中tag为PYTHON的tag字段全部修改为Python。
后台会通过执行'SELECT exam_id,tag,difficulty,duration,release_time FROM examination_info;'语句来对比结果。

 建表语句
drop table if EXISTS examination_info;
CREATE TABLE IF NOT EXISTS 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_bin;
TRUNCATE examination_info;
INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
(9001, 'SQL', 'hard', 60, '2020-01-01 10:00:00'),
(9002, 'python', 'easy', 60, '2020-01-01 10:00:00'),
(9003, 'Python', 'medium', 80, '2020-01-01 10:00:00'),
(9004, 'PYTHON', 'hard', 80, '2020-01-01 10:00:00');

 答案
UPDATE examination_info
set tag ='Python' WHERE tag='PYTHON';

在这里插入图片描述

SQL5 更新记录(二)

作答记录表exam_record表结构
在这里插入图片描述

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,submit_time为 完成时间
请把exam_record表中202191日之前开始作答的未完成记录全部改为被动完成,
即:将完成时间改为'2099-01-01 00:00:00',分数改为0。

 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-02 09:01:01', '2020-01-02 09:21:01', 80),
(1001, 9002, '2021-09-01 09:01:01', '2021-09-01 09:21:01', 90),
(1002, 9001, '2021-08-02 19:01:01', null, null),
(1002, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1003, 9001, '2021-09-02 12:01:01', null, null),
(1003, 9002, '2021-09-01 12:01:01', null, null);

 答案
UPDATE exam_record
set submit_time='2099-01-01 00:00:00',
    score=0
WHERE start_time<'2021-09-01' and submit_time is null

在这里插入图片描述

1.3 删除记录

SQL6 删除记录(一)

作答记录表exam_record表结构,start_time是试卷开始时间,submit_time 是交卷,即结束时间
在这里插入图片描述

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,
start_time是试卷开始时间
submit_time 是交卷,即结束时间
请删除exam_record表中作答时间小于5分钟整且分数不及格(及格线为60分)的记录;
后台会执行您的SQL,然后通过 SELECT * FROM exam_record; 语句来筛选出剩下的数据,与正确数据进行对比。

 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
TRUNCATE exam_record;
INSERT INTO exam_record(uid, exam_id, start_time, submit_time, score) VALUES
(1001, 9001, '2020-01-01 22:11:12', '2020-01-01 23:16:12', 50),
(1001, 9002, '2020-01-02 09:01:01', '2020-01-02 09:06:00', 58),
(1002, 9001, '2021-05-02 10:01:01', '2021-05-02 10:05:58', 60),
(1002, 9002, '2021-06-02 19:01:01', '2021-06-02 19:05:01', 54),
(1003, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 49),
(1003, 9001, '2021-09-05 19:01:01', '2021-09-05 19:15:01', 70),
(1003, 9001, '2021-09-06 19:01:01', '2021-09-06 19:05:01', 80),
(1003, 9002, '2021-09-09 07:01:02', null, null);

 答案
delete from exam_record
where timestampdiff(minute,start_time,submit_time) < 5 
and score < 60;

在这里插入图片描述

SQL7 删除记录(二)

作答记录表exam_record结构如下:
在这里插入图片描述

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,start_time是试卷开始时间
submit_time 是交卷时间,即结束时间,如果未完成的话,则为空
请删除exam_record表中未完成作答或作答时间小于5分钟整的记录中,开始作答时间最早的3条记录。
后台会通过 SELECT * FROM exam_record 语句来对比结果。

 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
TRUNCATE exam_record;
INSERT INTO exam_record(uid, exam_id, start_time, submit_time, score) VALUES
(1001, 9001, '2020-01-01 22:11:12', '2020-01-01 23:16:12', 50),
(1001, 9002, '2020-01-02 09:01:01', '2020-01-02 09:06:00', 58),
(1001, 9002, '2020-01-02 09:01:01', '2020-01-02 09:05:01', 58),
(1002, 9001, '2021-05-02 10:01:01', '2021-05-02 10:06:58', 60),
(1002, 9002, '2021-06-02 19:01:01', null, null),
(1003, 9001, '2021-09-05 19:01:01', null, null),
(1003, 9001, '2021-09-05 19:01:01', null, null),
(1003, 9002, '2021-09-09 07:01:02', null, null);

 答案
delete from exam_record
where timestampdiff(minute, start_time, submit_time) < 5
or submit_time is null
order by start_time
limit 3

在这里插入图片描述

SQL8 删除记录(三)

试卷作答记录表exam_record表结构
在这里插入图片描述

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,
请删除exam_record表中所有记录,并重置自增主键。
后台会通过SELECT table_rows, auto_increment FROM information_schema.tables WHERE table_name='exam_record'语句来对比输出结果


 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
TRUNCATE exam_record;
INSERT INTO exam_record(uid, exam_id, start_time, submit_time, score) VALUES
(1001, 9001, '2020-01-01 22:11:12', '2020-01-01 23:16:12', 50),
(1001, 9002, '2020-01-02 09:01:01', '2020-01-02 09:06:00', 58);

 答案
TRUNCATE table  exam_record;

在这里插入图片描述

2.表与索引操作

2.1 表的创建、修改与删除

SQL9 创建一张新表

原来的用户信息表
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第1张图片

 题目描述
现有一张用户信息表,其中包含多年来在平台注册过的用户信息,随着牛客平台的不断壮大,
用户量飞速增长,为了高效地为高活跃用户提供服务,现需要将部分用户拆分出一张新表。
作为数据分析师,请创建一张优质用户信息表user_info_vip,表结构和用户信息表一致。
请写出建表语句将表格中所有限制和说明记录到表里。

备注:
1.后台会通过 SHOW FULL FIELDS FROM user_info_vip 语句,来对比输出结果
2.如果该表已经被其他分析师创建过了,正常返回即可


 答案
create table if not exists user_info_vip (
    id int(11) primary key auto_increment comment '自增ID',
    uid int(11) unique not null comment '用户ID',
    nick_name varchar(64) comment '昵称',
    achievement int(11) default 0 comment '成就值',
    level int(11) comment '用户等级',
    job varchar(32) comment '职业方向',
    register_time datetime default current_timestamp comment '注册时间'
);

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第2张图片

SQL10 修改表

用户信息表user_info
在这里插入图片描述

 题目描述
现有一张用户信息表user_info,其中包含多年来在平台注册过的用户信息。
请在用户信息表,字段level的后面增加一列最多可保存15个汉字的字段school;
并将表中job列名改为profession,同时varchar字段长度变为10;
achievement的默认值设置为0。

备注:建表时限制的字符集为utf8,MySQL版本为8.*
后台会通过SHOW FULL FIELDS FROM user_info 来对比输出结果。


 建表语句
drop table if exists user_info;
CREATE TABLE IF NOT EXISTS user_info (
id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
uid int UNIQUE NOT NULL COMMENT '用户ID',
`nick_name` varchar(64) COMMENT '昵称',
achievement int COMMENT '成就值',
level int COMMENT '用户等级',
job varchar(10) COMMENT '职业方向',
register_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;


 答案
ALTER TABLE user_info ADD school varchar(15) after level;
ALTER TABLE user_info CHANGE job profession varchar(10);
ALTER TABLE user_info modify achievement int(11) DEFAULT 0;

在这里插入图片描述

SQL11 删除表

 题目描述
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录。
一般每年都会为exam_record表建立一张备份表exam_record_{YEAR},{YEAR}为对应年份。

现在随着数据越来越多,存储告急,请你把很久前的(20112014年)备份表都删掉(如果存在的话)。
备注:后台会通过SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME LIKE \'exam\_record\_201_\'  来对比输出结果。

 建表语句
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS 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;
CREATE TABLE IF NOT EXISTS exam_record_2010 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2012 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2013 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2014 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2015 (LIKE exam_record); 


 答案
drop table 
if exists 
exam_record_2011,
exam_record_2012,
exam_record_2013,
exam_record_2014;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第3张图片

2.2 索引的创建、删除

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第4张图片

SQL12 创建索引

根据题意,将返回如下结果:
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第5张图片

 题目描述
现有一张试卷信息表examination_info,其中包含各种类型试卷的信息。为了对表更方便快捷地查询,
需要在examination_info表创建以下索引,规则如下:
在duration列创建普通索引idx_duration、在exam_id列创建唯一性索引uniq_idx_exam_id、在tag列创建全文索引full_idx_tag。

 建表语句
drop table if exists examination_info;
CREATE TABLE IF NOT EXISTS 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_bin;


 答案
-- 唯一索引
ALTER TABLE examination_info
ADD UNIQUE INDEX uniq_idx_exam_id(exam_id);

-- 全文索引
ALTER TABLE examination_info
ADD FULLTEXT INDEX full_idx_tag(tag);
 
-- 普通索引
ALTER TABLE examination_info
ADD INDEX idx_duration(duration);

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第6张图片

SQL13 删除索引

 题目描述
请删除examination_info表上的唯一索引uniq_idx_exam_id和全文索引full_idx_tag。
后台会通过 SHOW INDEX FROM examination_info 来对比输出结果。

 建表语句
drop table if exists examination_info;
CREATE TABLE IF NOT EXISTS examination_info (
id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
exam_id int COMMENT '试卷ID',
tag varchar(32) COMMENT '类别标签',
difficulty varchar(8) COMMENT '难度',
duration int NOT NULL COMMENT '时长(分钟数)',
release_time datetime COMMENT '发布时间'
)CHARACTER SET utf8 COLLATE utf8_bin;
CREATE INDEX idx_duration ON examination_info(duration);
CREATE UNIQUE INDEX uniq_idx_exam_id ON examination_info(exam_id);
ALTER TABLE examination_info ADD FULLTEXT full_idx_tag(tag);

 答案
drop  index uniq_idx_exam_id on examination_info;
drop index full_idx_tag on examination_info;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第7张图片

3.聚合分组查询

3.1 聚合函数

SQL14 SQL类别高难度试卷得分的截断平均值

examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第8张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第9张图片

 题目描述
牛客的运营同学想要查看大家在SQL类别中高难度试卷的得分情况。
请你帮她从exam_record数据表中计算所有用户完成SQL类别高难度试卷得分的截断平均值(去掉一个最大值和一个最小值后的平均值)

示例数据:examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间)
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

示例数据:exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-02 09:01:01 | 2020-01-02 09:21:01 |    80 |
|  2 | 1001 |    9001 | 2021-05-02 10:01:01 | 2021-05-02 10:30:01 |    81 |
|  3 | 1001 |    9001 | 2021-06-02 19:01:01 | 2021-06-02 19:31:01 |    84 |
|  4 | 1001 |    9002 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    89 |
|  5 | 1001 |    9001 | 2021-09-02 12:01:01 | NULL                |  NULL |
|  6 | 1001 |    9002 | 2021-09-01 12:01:01 | NULL                |  NULL |
|  7 | 1002 |    9002 | 2021-02-02 19:01:01 | 2021-02-02 19:30:01 |    87 |
|  8 | 1002 |    9001 | 2021-05-05 18:01:01 | 2021-05-05 18:59:02 |    90 |
|  9 | 1003 |    9001 | 2021-02-06 12:01:01 | NULL                |  NULL |
| 10 | 1003 |    9001 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    50 |
+----+------+---------+---------------------+---------------------+-------+

从examination_info表可知,试卷9001为高难度SQL试卷,该试卷被作答的得分有[80,81,84,90,50],
去除最高分和最低分后为[80,81,84],平均分为81.6666667,保留一位小数后为81.7

根据输入你的查询结果如下:
+------+------------+-----------+
| tag  | difficulty | avg_score |
+------+------------+-----------+
| SQL  | hard       |      81.7 |
+------+------------+-----------+

 建表语句
drop table if exists examination_info;
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;

drop table if exists exam_record;
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, '2020-01-01 10:00:00'),
  (9002, '算法', 'medium', 80, '2020-08-02 10:00:00');

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-02 09:01:01', '2020-01-02 09:21:01', 80),
(1001, 9001, '2021-05-02 10:01:01', '2021-05-02 10:30:01', 81),
(1001, 9001, '2021-06-02 19:01:01', '2021-06-02 19:31:01', 84),
(1001, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1001, 9001, '2021-09-02 12:01:01', null, null),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1002, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1002, 9001, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90),
(1003, 9001, '2021-02-06 12:01:01', null, null),
(1003, 9001, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 50);

 答案
select tag,difficulty,
round((sum(score)-min(score)-max(score))/
      (count(score)-2),1) as avg_score
from examination_info 
join exam_record using(exam_id)
where tag='SQL' and difficulty='hard';

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第10张图片

SQL15 统计作答次数

exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第11张图片

 题目描述
有一个试卷作答记录表exam_record,请从中统计出总作答次数total_pv、试卷已完成作答数complete_pv、已完成的试卷数complete_exam_cnt。
示例数据 exam_record表(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-02 09:01:01 | 2020-01-02 09:21:01 |    80 |
|  2 | 1001 |    9001 | 2021-05-02 10:01:01 | 2021-05-02 10:30:01 |    81 |
|  3 | 1001 |    9001 | 2021-06-02 19:01:01 | 2021-06-02 19:31:01 |    84 |
|  4 | 1001 |    9002 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    89 |
|  5 | 1001 |    9001 | 2021-09-02 12:01:01 | NULL                |  NULL |
|  6 | 1001 |    9002 | 2021-09-01 12:01:01 | NULL                |  NULL |
|  7 | 1002 |    9002 | 2021-02-02 19:01:01 | 2021-02-02 19:30:01 |    87 |
|  8 | 1002 |    9001 | 2021-05-05 18:01:01 | 2021-05-05 18:59:02 |    90 |
|  9 | 1003 |    9001 | 2021-02-06 12:01:01 | NULL                |  NULL |
| 10 | 1003 |    9001 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    89 |
| 11 | 1004 |    9001 | 2021-09-06 12:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

示例输出:
+----------+--------------+-------------------+
| total_pv | compelete_pv | complete_exam_cnt |
+----------+--------------+-------------------+
|       11 |            7 |                 2 |
+----------+--------------+-------------------+
解释:表示截止当前,有11次试卷作答记录,已完成的作答次数为7次(中途退出的为未完成状态,其交卷时间和份数为NULL),
已完成的试卷有90019002两份。


 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-02 09:01:01', '2020-01-02 09:21:01', 80),
(1001, 9001, '2021-05-02 10:01:01', '2021-05-02 10:30:01', 81),
(1001, 9001, '2021-06-02 19:01:01', '2021-06-02 19:31:01', 84),
(1001, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1001, 9001, '2021-09-02 12:01:01', null, null),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1002, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1002, 9001, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90),
(1003, 9001, '2021-02-06 12:01:01', null, null),
(1003, 9001, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 89),
(1004, 9001, '2021-09-06 12:01:01', null, null);

 答案
select 
DISTINCT count(*) as total_pv,
count(submit_time) as compelete_pv,
count(distinct exam_id and score IS not NULL) as complete_exam_cnt
from exam_record;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第12张图片

SQL16 得分不小于平均分的最低分

examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第13张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第14张图片

 题目描述
请从试卷作答记录表中找到SQL试卷得分不小于该类试卷平均得分的用户最低得分。
示例数据 exam_record表(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-02 09:01:01 | 2020-01-02 09:21:01 |    80 |
|  2 | 1002 |    9001 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    89 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | NULL                |  NULL |
|  4 | 1002 |    9003 | 2021-09-01 12:01:01 | NULL                |  NULL |
|  5 | 1002 |    9001 | 2021-02-02 19:01:01 | 2021-02-02 19:30:01 |    87 |
|  6 | 1002 |    9002 | 2021-05-05 18:01:01 | 2021-05-05 18:59:02 |    90 |
|  7 | 1003 |    9002 | 2021-02-06 12:01:01 | NULL                |  NULL |
|  8 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
|  9 | 1004 |    9003 | 2021-09-06 12:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

examination_info表(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间)
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | SQL    | easy       |       60 | 2020-02-01 10:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

示例输出数据:
+--------------------+
| min_score_over_avg |
+--------------------+
|                 87 |
+--------------------+

保证至少有一个有效的SQL类别的试卷作答分数
解释:试卷90019002SQL类别,作答这两份试卷的得分有[80,89,87,90],平均分为86.5,不小于平均分的最小分数为87

 建表语句
drop table if exists examination_info;
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;

drop table if exists exam_record;
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, '2020-01-01 10:00:00'),
  (9002, 'SQL', 'easy', 60, '2020-02-01 10:00:00'),
  (9003, '算法', 'medium', 80, '2020-08-02 10:00:00');

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-02 09:01:01', '2020-01-02 09:21:01', 80),
(1002, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1002, 9002, '2021-09-02 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', null, null),
(1002, 9001, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1002, 9002, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90),
(1003, 9002, '2021-02-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1004, 9003, '2021-09-06 12:01:01', null, null);

 答案
select min(score) as min_score_over_avg
from examination_info as i 
join exam_record as r
on i.exam_id = r.exam_id
where tag = 'SQL'
and score >= (select avg(score)
              from examination_info as i 
              join exam_record as r
              on i.exam_id = r.exam_id
              where tag = 'SQL');

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第15张图片

3.2 分组查询

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第16张图片

SQL17 平均活跃天数和月活人数

exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第17张图片

 题目描述
用户在牛客试卷作答区作答记录存储在表exam_record中,内容如下:
exam_record表(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-07-02 09:01:01 | 2021-07-02 09:21:01 |    80 |
|  2 | 1002 |    9001 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    81 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | NULL                |  NULL |
|  4 | 1002 |    9003 | 2021-09-01 12:01:01 | NULL                |  NULL |
|  5 | 1002 |    9001 | 2021-07-02 19:01:01 | 2021-07-02 19:30:01 |    82 |
|  6 | 1002 |    9002 | 2021-07-05 18:01:01 | 2021-07-05 18:59:02 |    90 |
|  7 | 1003 |    9002 | 2021-07-06 12:01:01 | NULL                |  NULL |
|  8 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
|  9 | 1004 |    9003 | 2021-09-06 12:01:01 | NULL                |  NULL |
| 10 | 1002 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
| 11 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 12 | 1006 |    9002 | 2021-09-02 12:11:01 | 2021-09-02 12:31:01 |    89 |
| 13 | 1007 |    9002 | 2020-09-02 12:11:01 | 2020-09-02 12:31:01 |    89 |
+----+------+---------+---------------------+---------------------+-------+

请计算2021年每个月里试卷作答区用户平均月活跃天数avg_active_days和月度活跃人数mau,上面数据的示例输出如下:
+--------+-----------------+-----+
| month  | avg_active_days | mau |
+--------+-----------------+-----+
| 202107 |            1.50 |   2 |
| 202109 |            1.25 |   4 |
+--------+-----------------+-----+

解释:20217月有2人活跃,共活跃了3天(1001活跃1天,1002活跃2天),平均活跃天数1.520219月有4人活跃,共活跃了5天,平均活跃天数1.25,结果保留2位小数。
注:此处活跃指有交卷行为。


 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-07-02 09:01:01', '2021-07-02 09:21:01', 80),
(1002, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 81),
(1002, 9002, '2021-09-02 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', null, null),
(1002, 9001, '2021-07-02 19:01:01', '2021-07-02 19:30:01', 82),
(1002, 9002, '2021-07-05 18:01:01', '2021-07-05 18:59:02', 90),
(1003, 9002, '2021-07-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1004, 9003, '2021-09-06 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 81),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1006, 9002, '2021-09-02 12:11:01', '2021-09-02 12:31:01', 89),
(1007, 9002, '2020-09-02 12:11:01', '2020-09-02 12:31:01', 89);

 答案
select concat(substr(submit_time,1,4),substr(submit_time,6,2)) as month
, round(count(distinct uid, day(submit_time))/count(distinct uid),2) as avg_active_days
, round(count(distinct(uid)),0) as mau
from exam_record
where submit_time is not null
and year(submit_time) ='2021'
group by month;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第18张图片

SQL18 月总刷题数和日均刷题数

practice_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第19张图片

 题目描述
现有一张题目练习记录表practice_record,示例内容如下:
+----+------+-------------+---------------------+-------+
| id | uid  | question_id | submit_time         | score |
+----+------+-------------+---------------------+-------+
|  1 | 1001 |        8001 | 2021-08-02 11:41:01 |    60 |
|  2 | 1002 |        8001 | 2021-09-02 19:30:01 |    50 |
|  3 | 1002 |        8001 | 2021-09-02 19:20:01 |    70 |
|  4 | 1002 |        8002 | 2021-09-02 19:38:01 |    70 |
|  5 | 1003 |        8002 | 2021-08-01 19:38:01 |    80 |
+----+------+-------------+---------------------+-------+


请从中统计出2021年每个月里用户的月总刷题数month_q_cnt 和日均刷题数avg_day_q_cnt(按月份升序排序)以及该年的总体情况,示例数据输出如下:
+--------------+-------------+---------------+
| submit_month | month_q_cnt | avg_day_q_cnt |
+--------------+-------------+---------------+
| 202108       |           2 |         0.065 |
| 202109       |           3 |         0.100 |
| 2021汇总     |           5 |         0.161 |
+--------------+-------------+---------------+

解释:20218月共有2次刷题记录,日均刷题数为2/31=0.065(保留3位小数);
20219月共有3次刷题记录,日均刷题数为3/30=0.1002021年共有5次刷题记录(年度汇总平均无实际意义,这里我们按照31天来算5/31=0.161)



 建表语句
drop table if exists practice_record;
CREATE TABLE  practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1002, 8001, '2021-09-02 19:30:01', 50),
(1002, 8001, '2021-09-02 19:20:01', 70),
(1002, 8002, '2021-09-02 19:38:01', 70),
(1003, 8002, '2021-08-01 19:38:01', 80);


 答案
SELECT IFNULL(sm, "2021汇总") submit_month
       , COUNT(question_id) month_q_cnt
       , ROUND(COUNT(question_id) / MAX(DAY(LAST_DAY(submit_time))),3) avg_day_q_cnt
FROM (SELECT *, DATE_FORMAT(submit_time, "%Y%m") sm FROM practice_record) t1
WHERE YEAR(submit_time) = 2021
GROUP BY sm WITH ROLLUP
ORDER BY submit_month;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第20张图片

SQL19 未完成试卷数大于1的有效用户

examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第21张图片
practice_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第22张图片

 题目描述
现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分),示例数据如下:
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-07-02 09:01:01 | 2021-07-02 09:21:01 |    80 |
|  2 | 1002 |    9001 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    81 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | NULL                |  NULL |
|  4 | 1002 |    9003 | 2021-09-01 12:01:01 | NULL                |  NULL |
|  5 | 1002 |    9001 | 2021-07-02 19:01:01 | 2021-07-02 19:30:01 |    82 |
|  6 | 1002 |    9002 | 2021-07-05 18:01:01 | 2021-07-05 18:59:02 |    90 |
|  7 | 1003 |    9002 | 2021-07-06 12:01:01 | NULL                |  NULL |
|  8 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
|  9 | 1004 |    9003 | 2021-09-06 12:01:01 | NULL                |  NULL |
| 10 | 1002 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
| 11 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 12 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 13 | 1006 |    9002 | 2021-09-02 12:11:01 | 2021-09-02 12:31:01 |    89 |
+----+------+---------+---------------------+---------------------+-------+

还有一张试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间),示例数据如下:
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | SQL    | easy       |       60 | 2020-02-01 10:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+


请统计2021年每个未完成试卷作答数大于1的有效用户的数据(有效用户指完成试卷作答数至少为1且未完成数小于5),
输出用户ID、未完成试卷作答数、完成试卷作答数、作答过的试卷tag集合,按未完成试卷数量由多到少排序。示例数据的输出结果如下:
+------+----------------+--------------+-------------------------------------------------------------------------------+
| uid  | incomplete_cnt | complete_cnt | detail                                                                        |
+------+----------------+--------------+-------------------------------------------------------------------------------+
| 1002 |              2 |            4 | 2021-07-02:SQL;2021-07-05:SQL;2021-09-01:算法;2021-09-02:SQL;2021-09-05:SQL   |
+------+----------------+--------------+-------------------------------------------------------------------------------+

解释:2021年的作答记录中,除了1004,其他用户均满足有效用户定义,但只有1002未完成试卷数大于1,
因此只输出1002,detail中是1002作答过的试卷{日期:tag}集合,日期和tag间用:连接,多元素间用;连接。


 建表语句
drop table if exists examination_info;
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;

drop table if exists exam_record;
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, '2020-01-01 10:00:00'),
  (9002, 'SQL', 'easy', 60, '2020-02-01 10:00:00'),
  (9003, '算法', 'medium', 80, '2020-08-02 10:00:00');

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-07-02 09:01:01', '2021-07-02 09:21:01', 80),
(1002, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 81),
(1002, 9002, '2021-09-02 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', null, null),
(1002, 9001, '2021-07-02 19:01:01', '2021-07-02 19:30:01', 82),
(1002, 9002, '2021-07-05 18:01:01', '2021-07-05 18:59:02', 90),
(1003, 9002, '2021-07-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1004, 9003, '2021-09-06 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 81),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1006, 9002, '2021-09-02 12:11:01', '2021-09-02 12:31:01', 89);

 答案
SELECT uid, count(incomplete) as incomplete_cnt,
    count(complete) as complete_cnt,
    group_concat(distinct concat_ws(':', date(start_time), tag) SEPARATOR ';') as detail
from (
    SELECT uid, tag, start_time,
        if(submit_time is null, 1, null) as incomplete,
        if(submit_time is null, null, 1) as complete
    from exam_record 
    left join examination_info using(exam_id)
    where year(start_time)=2021
) as exam_complete_rec
group by uid
having complete_cnt >= 1 and incomplete_cnt BETWEEN 2 and 4
order by incomplete_cnt DESC;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第23张图片

4.多表查询

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第24张图片

4.1 嵌套子查询

SQL20 月均完成试卷数不小于3的用户爱作答的类别

examination_info表结构
在这里插入图片描述
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第25张图片

 题目描述
现有试卷作答记录表exam_record(uid:用户ID, exam_id:试卷ID, start_time:开始作答时间, submit_time:交卷时间,没提交的话为NULL, score:得分),示例数据如下:
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-07-02 09:01:01 | NULL                |  NULL |
|  2 | 1002 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:21:01 |    60 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | 2021-09-02 12:31:01 |    70 |
|  4 | 1002 |    9001 | 2021-09-05 19:01:01 | 2021-09-05 19:40:01 |    81 |
|  5 | 1002 |    9002 | 2021-07-06 12:01:01 | NULL                |  NULL |
|  6 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
|  7 | 1003 |    9003 | 2021-09-08 12:01:01 | 2021-09-08 12:11:01 |    40 |
|  8 | 1003 |    9001 | 2021-09-08 13:01:01 | NULL                |  NULL |
|  9 | 1003 |    9002 | 2021-09-08 14:01:01 | NULL                |  NULL |
| 10 | 1003 |    9003 | 2021-09-08 15:01:01 | NULL                |  NULL |
| 11 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 12 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 13 | 1005 |    9002 | 2021-09-02 12:11:01 | 2021-09-02 12:31:01 |    89 |
+----+------+---------+---------------------+---------------------+-------+

试卷信息表examination_info(exam_id:试卷ID, tag:试卷类别, difficulty:试卷难度, duration:考试时长, release_time:发布时间),
示例数据如下:
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | C++    | easy       |       60 | 2020-02-01 10:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

请从表中统计出 “当月均完成试卷数”不小于3的用户们爱作答的类别及作答次数,按次数降序输出,示例输出如下:

解释:用户10021005202109月的完成试卷数目均为3,其他用户均小于3;
然后用户10021005作答过的试卷tag分布结果按作答次数降序排序依次为C++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, '2020-01-01 10:00:00'),
  (9002, 'C++', 'easy', 60, '2020-02-01 10:00:00'),
  (9003, '算法', 'medium', 80, '2020-08-02 10:00:00');

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-07-02 09:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:21:01', 60),
(1002, 9002, '2021-09-02 12:01:01', '2021-09-02 12:31:01', 70),
(1002, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 81),
(1002, 9002, '2021-07-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1003, 9003, '2021-09-08 12:01:01', '2021-09-08 12:11:01', 40),
(1003, 9001, '2021-09-08 13:01:01', null, null),
(1003, 9002, '2021-09-08 14:01:01', null, null),
(1003, 9003, '2021-09-08 15:01:01', null, null),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1005, 9002, '2021-09-02 12:11:01', '2021-09-02 12:31:01', 89);


 答案
select tag, count(start_time) as tag_cnt
from exam_record er inner join examination_info ei
on er.exam_id = ei.exam_id
where uid in 
(select uid
from exam_record er 
group by uid, month(start_time)
having count(submit_time) >= 3)
group by tag
order by tag_cnt desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第26张图片

SQL21 试卷发布当天作答人数和平均分

user_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第27张图片
examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第28张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第29张图片

 题目描述
现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间),示例数据如下:
+----+------+------------+-------------+-------+--------+---------------------+
| id | uid  | nick_name  | achievement | level | job    | register_time       |
+----+------+------------+-------------+-------+--------+---------------------+
|  1 | 1001 | 牛客1|        3100 |     7 | 算法   | 2020-01-01 10:00:00 |
|  2 | 1002 | 牛客2|        2100 |     6 | 算法   | 2020-01-01 10:00:00 |
|  3 | 1003 | 牛客3|        1500 |     5 | 算法   | 2020-01-01 10:00:00 |
|  4 | 1004 | 牛客4|        1100 |     4 | 算法   | 2020-01-01 10:00:00 |
|  5 | 1005 | 牛客5|        1600 |     6 | C++    | 2020-01-01 10:00:00 |
|  6 | 1006 | 牛客6|        3000 |     6 | C++    | 2020-01-01 10:00:00 |
+----+------+------------+-------------+-------+--------+---------------------+
释义:用户1001昵称为牛客1号,成就值为3100,用户等级是7级,职业方向为算法,注册时间2020-01-01 10:00:00

试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间) 示例数据如下:
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | easy       |       60 | 2020-02-01 10:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分) 示例数据如下:
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:41:01 |    70 |
|  2 | 1002 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:21:01 |    60 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | 2021-09-02 12:31:01 |    70 |
|  4 | 1002 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    80 |
|  5 | 1002 |    9003 | 2021-08-01 12:01:01 | 2021-08-01 12:21:01 |    60 |
|  6 | 1002 |    9002 | 2021-08-02 12:01:01 | 2021-08-02 12:31:01 |    70 |
|  7 | 1002 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    85 |
|  8 | 1002 |    9002 | 2021-07-06 12:01:01 | NULL                |  NULL |
|  9 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
| 10 | 1003 |    9003 | 2021-09-08 12:01:01 | 2021-09-08 12:11:01 |    40 |
| 11 | 1003 |    9001 | 2021-09-01 13:01:01 | 2021-09-01 13:41:01 |    70 |
| 12 | 1003 |    9002 | 2021-09-08 14:01:01 | NULL                |  NULL |
| 13 | 1003 |    9003 | 2021-09-08 15:01:01 | NULL                |  NULL |
| 14 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    90 |
| 15 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 16 | 1005 |    9002 | 2021-09-02 12:11:01 | 2021-09-02 12:31:01 |    89 |
+----+------+---------+---------------------+---------------------+-------+

请计算每张SQL类别试卷发布后,当天5级以上的用户作答的人数uv和平均分avg_score,按人数降序,相同人数的按平均分升序,示例数据结果输出如下:
+---------+----+-----------+
| exam_id | uv | avg_score |
+---------+----+-----------+
|    9001 |  3 |      81.3 |
+---------+----+-----------+

解释:只有一张SQL类别的试卷,试卷ID为9001,发布当天(2021-09-01)有1001100210031005作答过,
但是10035级用户,其他3位为5级以上,他们三的得分有[70,80,85,90],平均分为81.3(保留1位小数)。


 建表语句
drop table if exists examination_info,user_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 user_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int UNIQUE NOT NULL COMMENT '用户ID',
    `nick_name` varchar(64) COMMENT '昵称',
    achievement int COMMENT '成就值',
    level int COMMENT '用户等级',
    job varchar(32) COMMENT '职业方向',
    register_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 user_info(uid,`nick_name`,achievement,level,job,register_time) VALUES
  (1001, '牛客1号', 3100, 7, '算法', '2020-01-01 10:00:00'),
  (1002, '牛客2号', 2100, 6, '算法', '2020-01-01 10:00:00'),
  (1003, '牛客3号', 1500, 5, '算法', '2020-01-01 10:00:00'),
  (1004, '牛客4号', 1100, 4, '算法', '2020-01-01 10:00:00'),
  (1005, '牛客5号', 1600, 6, 'C++', '2020-01-01 10:00:00'),
  (1006, '牛客6号', 3000, 6, 'C++', '2020-01-01 10:00:00');

INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
  (9001, 'SQL', 'hard', 60, '2021-09-01 06:00:00'),
  (9002, 'C++', 'easy', 60, '2020-02-01 10:00:00'),
  (9003, '算法', 'medium', 80, '2020-08-02 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:41:01', 70),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:21:01', 60),
(1002, 9002, '2021-09-02 12:01:01', '2021-09-02 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 80),
(1002, 9003, '2021-08-01 12:01:01', '2021-08-01 12:21:01', 60),
(1002, 9002, '2021-08-02 12:01:01', '2021-08-02 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 85),
(1002, 9002, '2021-07-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1003, 9003, '2021-09-08 12:01:01', '2021-09-08 12:11:01', 40),
(1003, 9001, '2021-09-01 13:01:01', '2021-09-01 13:41:01', 70),
(1003, 9002, '2021-09-08 14:01:01', null, null),
(1003, 9003, '2021-09-08 15:01:01', null, null),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 90),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1005, 9002, '2021-09-02 12:11:01', '2021-09-02 12:31:01', 89);

 答案
SELECT
    exam_id,
    count( DISTINCT uid ) AS uv,
    ROUND(avg( score ), 1) AS avg_score
FROM exam_record
WHERE (exam_id, DATE(start_time)) IN (
    SELECT exam_id, DATE(release_time)
    FROM examination_info WHERE tag = "SQL"
) AND uid IN ( SELECT uid FROM user_info WHERE `level` > 5 )
GROUP BY exam_id
ORDER BY uv DESC, avg_score ASC;
备注:
结果按人数uv降序,相同人数的按平均分升序

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第30张图片

SQL22 作答试卷得分大于过80的人的用户等级分布

user_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第31张图片
examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第32张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第33张图片

 题目描述
现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间),示例数据如下:
+----+------+------------+-------------+-------+--------+---------------------+
| id | uid  | nick_name  | achievement | level | job    | register_time       |
+----+------+------------+-------------+-------+--------+---------------------+
|  1 | 1001 | 牛客1|        3100 |     7 | 算法   | 2020-01-01 10:00:00 |
|  2 | 1002 | 牛客2|        2100 |     6 | 算法   | 2020-01-01 10:00:00 |
|  3 | 1003 | 牛客3|        1500 |     5 | 算法   | 2020-01-01 10:00:00 |
|  4 | 1004 | 牛客4|        1100 |     4 | 算法   | 2020-01-01 10:00:00 |
|  5 | 1005 | 牛客5|        1600 |     6 | C++    | 2020-01-01 10:00:00 |
|  6 | 1006 | 牛客6|        3000 |     6 | C++    | 2020-01-01 10:00:00 |
+----+------+------------+-------------+-------+--------+---------------------+
释义:用户1001昵称为牛客1号,成就值为3100,用户等级是7级,职业方向为算法,注册时间2020-01-01 10:00:00

试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间) 示例数据如下:
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | easy       |       60 | 2020-02-01 10:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2020-08-02 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分) 示例数据如下:
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:41:01 |    70 |
|  2 | 1002 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:21:01 |    60 |
|  3 | 1002 |    9002 | 2021-09-02 12:01:01 | 2021-09-02 12:31:01 |    70 |
|  4 | 1002 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    80 |
|  5 | 1002 |    9003 | 2021-08-01 12:01:01 | 2021-08-01 12:21:01 |    60 |
|  6 | 1002 |    9002 | 2021-08-02 12:01:01 | 2021-08-02 12:31:01 |    70 |
|  7 | 1002 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    85 |
|  8 | 1002 |    9002 | 2021-07-06 12:01:01 | NULL                |  NULL |
|  9 | 1003 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:31:01 |    86 |
| 10 | 1003 |    9003 | 2021-09-08 12:01:01 | 2021-09-08 12:11:01 |    40 |
| 11 | 1003 |    9001 | 2021-09-01 13:01:01 | 2021-09-01 13:41:01 |    70 |
| 12 | 1003 |    9002 | 2021-09-08 14:01:01 | NULL                |  NULL |
| 13 | 1003 |    9003 | 2021-09-08 15:01:01 | NULL                |  NULL |
| 14 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    90 |
| 15 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    88 |
| 16 | 1005 |    9002 | 2021-09-02 12:11:01 | 2021-09-02 12:31:01 |    89 |
+----+------+---------+---------------------+---------------------+-------+

统计作答SQL类别的试卷得分大于过80的人的用户等级分布,按数量降序排序(保证数量都不同)。
示例数据结果输出如下:

解释:9001SQL类试卷,作答该试卷大于80分的人有1002100310053人,6级两人,5级一人。


 建表语句
drop table if exists examination_info;
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;

drop table if exists user_info;
CREATE TABLE user_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int UNIQUE NOT NULL COMMENT '用户ID',
    `nick_name` varchar(64) COMMENT '昵称',
    achievement int COMMENT '成就值',
    level int COMMENT '用户等级',
    job varchar(32) COMMENT '职业方向',
    register_time datetime COMMENT '注册时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

drop table if exists exam_record;
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 user_info(uid,`nick_name`,achievement,level,job,register_time) VALUES
  (1001, '牛客1号', 3100, 7, '算法', '2020-01-01 10:00:00'),
  (1002, '牛客2号', 2100, 6, '算法', '2020-01-01 10:00:00'),
  (1003, '牛客3号', 1500, 5, '算法', '2020-01-01 10:00:00'),
  (1004, '牛客4号', 1100, 4, '算法', '2020-01-01 10:00:00'),
  (1005, '牛客5号', 1600, 6, 'C++', '2020-01-01 10:00:00'),
  (1006, '牛客6号', 3000, 6, 'C++', '2020-01-01 10:00:00');

INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
  (9001, 'SQL', 'hard', 60, '2021-09-01 06:00:00'),
  (9002, 'C++', 'easy', 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:41:01', 79),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:21:01', 60),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 80),
(1002, 9003, '2021-08-01 12:01:01', '2021-08-01 12:21:01', 60),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 85),
(1002, 9002, '2021-09-01 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1003, 9003, '2021-09-08 12:01:01', '2021-09-08 12:11:01', 40),
(1003, 9001, '2021-09-01 13:01:01', '2021-09-01 13:41:01', 81),
(1003, 9002, '2021-09-01 14:01:01', null, null),
(1003, 9003, '2021-09-08 15:01:01', null, null),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 90),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1006, 9002, '2021-09-01 12:11:01', '2021-09-01 12:31:01', 89);


 答案
SELECT level, COUNT(DISTINCT uid) AS level_cnt
FROM exam_record er JOIN user_info ui USING(uid)
JOIN examination_info ei USING(exam_id)
WHERE ei.tag='SQL' AND er.score > 80
GROUP BY level
ORDER BY COUNT(DISTINCT uid) DESC, level DESC;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第34张图片

4.2 合并查询

SQL23 每个题目和每份试卷被作答的人数和次数

exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第35张图片
practice_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第36张图片

 题目描述
现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:41:01 |    81 |
|  2 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    70 |
|  3 | 1002 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    80 |
|  4 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    70 |
|  5 | 1004 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    85 |
|  6 | 1002 |    9002 | 2021-09-01 12:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

题目练习表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):
+----+------+-------------+---------------------+-------+
| id | uid  | question_id | submit_time         | score |
+----+------+-------------+---------------------+-------+
|  1 | 1001 |        8001 | 2021-08-02 11:41:01 |    60 |
|  2 | 1002 |        8001 | 2021-09-02 19:30:01 |    50 |
|  3 | 1002 |        8001 | 2021-09-02 19:20:01 |    70 |
|  4 | 1002 |        8002 | 2021-09-02 19:38:01 |    70 |
|  5 | 1003 |        8001 | 2021-08-02 19:38:01 |    70 |
|  6 | 1003 |        8001 | 2021-08-02 19:48:01 |    90 |
|  7 | 1003 |        8002 | 2021-08-01 19:38:01 |    80 |
+----+------+-------------+---------------------+-------+

请统计每个题目和每份试卷被作答的人数和次数,分别按照"试卷""题目"的uv & pv降序显示,示例数据结果输出如下:
+------+----+----+
| tid  | uv | pv |
+------+----+----+
| 9001 |  3 |  3 |
| 9002 |  1 |  3 |
| 8001 |  3 |  5 |
| 8002 |  2 |  2 |
+------+----+----+
解释:“试卷”有3人共练习3次试卷90011人作答39002;“刷题”有3人刷58001,有2人刷28002


 建表语句
drop table if exists practice_record;
CREATE TABLE  practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

drop table if exists exam_record;
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 practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1002, 8001, '2021-09-02 19:30:01', 50),
(1002, 8001, '2021-09-02 19:20:01', 70),
(1002, 8002, '2021-09-02 19:38:01', 70),
(1003, 8001, '2021-08-02 19:38:01', 70),
(1003, 8001, '2021-08-02 19:48:01', 90),
(1003, 8002, '2021-08-01 19:38:01', 80);

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:41:01', 81),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 80),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1004, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 85),
(1002, 9002, '2021-09-01 12:01:01', null, null);


 答案
SELECT exam_id as tid, 
  count(distinct uid) as uv,
  count(uid) as pv
from exam_record
group by exam_id
union ALL
SELECT question_id as tid,
  count(distinct uid) as uv,
  count(uid) as pv
from practice_record
group by question_id
order by LEFT(tid,1) DESC,uv DESC,pv DESC;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第37张图片

SQL24 分别满足两个活动的人

examination_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第38张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第39张图片

 题目描述
为了促进更多用户在牛客平台学习和刷题进步,我们会经常给一些既活跃又表现不错的用户发放福利。
假使以前我们有两拨运营活动,分别给每次试卷得分都能到85分的人(activity1)、
至少有一次用了一半时间就完成高难度试卷且分数大于80的人(activity2)发了福利券。

现在,需要你一次性将这两个活动满足的人筛选出来,交给运营同学。
请写出一个SQL实现:输出2021年里,所有每次试卷得分都能到85分的人以及至少有一次用了一半时间就完成高难度试卷且分数大于80的人的id和活动号,
按用户ID排序输出。

现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | hard       |       60 | 2021-09-01 06:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2021-09-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    81 |
|  2 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    70 |
|  3 | 1003 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    86 |
|  4 | 1003 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:51 |    89 |
|  5 | 1004 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:30:01 |    85 |
+----+------+---------+---------------------+---------------------+-------+

示例数据输出结果:
+------+-----------+
| uid  | activity  |
+------+-----------+
| 1001 | activity2 |
| 1003 | activity1 |
| 1004 | activity1 |
| 1004 | activity2 |
+------+-----------+

解释:用户1001最小分数81不满足活动1,但2959秒完成了60分钟长的试卷得分81,满足活动21003最小分数86满足活动1,完成时长都大于试卷时长的一半,不满足活动2;
用户1004刚好用了一半时间(30分钟整)完成了试卷得分85,满足活动1和活动2。


 建表语句
drop table if exists examination_info;
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;


drop table if exists exam_record;
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:31:00', 81),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1003, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 86),
(1003, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:51', 89),
(1004, 9001, '2021-09-01 19:01:01', '2021-09-01 19:30:01', 85);

 答案
(select r.uid, 'activity1' as activity
from exam_record r
where year(submit_time) = 2021 
group by r.uid
having min(score) >= 85)
union all
(select r.uid,'activity2' as activity 
from exam_record r
left join examination_info i on r.exam_id = i.exam_id
where year(submit_time) = 2021 and i.difficulty = 'hard' and score >=80 and 
            timestampdiff(second,r.start_time,r.submit_time)<= i.duration*30
group by r.uid)
order by uid;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第40张图片

4.3 连接查询

SQL25 满足条件的用户的试卷完成数和题目练习数

user_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第41张图片
examination_info表结构牛客刷题-SQL进阶挑战大总结(细节狂魔)_第42张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第43张图片
practice_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第44张图片

 题目描述
现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):
+----+------+------------+-------------+-------+--------+---------------------+
| id | uid  | nick_name  | achievement | level | job    | register_time       |
+----+------+------------+-------------+-------+--------+---------------------+
|  1 | 1001 | 牛客1|        3100 |     7 | 算法   | 2020-01-01 10:00:00 |
|  2 | 1002 | 牛客2|        2300 |     7 | 算法   | 2020-01-01 10:00:00 |
|  3 | 1003 | 牛客3|        2500 |     7 | 算法   | 2020-01-01 10:00:00 |
|  4 | 1004 | 牛客4|        1200 |     5 | 算法   | 2020-01-01 10:00:00 |
|  5 | 1005 | 牛客5|        1600 |     6 | C++    | 2020-01-01 10:00:00 |
|  6 | 1006 | 牛客6|        2000 |     6 | C++    | 2020-01-01 10:00:00 |
+----+------+------------+-------------+-------+--------+---------------------+

试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | hard       |       60 | 2021-09-01 06:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2021-09-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    81 |
|  2 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
|  3 | 1003 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    86 |
|  4 | 1003 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:51 |    89 |
|  5 | 1004 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:30:01 |    85 |
|  6 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:02 |    85 |
|  7 | 1006 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:21:01 |    84 |
|  8 | 1006 |    9001 | 2021-09-07 10:01:01 | 2021-09-07 10:21:01 |    80 |
+----+------+---------+---------------------+---------------------+-------+

题目练习记录表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):
+----+------+-------------+---------------------+-------+
| id | uid  | question_id | submit_time         | score |
+----+------+-------------+---------------------+-------+
|  1 | 1001 |        8001 | 2021-08-02 11:41:01 |    60 |
|  2 | 1002 |        8001 | 2021-09-02 19:30:01 |    50 |
|  3 | 1002 |        8001 | 2021-09-02 19:20:01 |    70 |
|  4 | 1002 |        8002 | 2021-09-02 19:38:01 |    70 |
|  5 | 1004 |        8001 | 2021-08-02 19:38:01 |    70 |
|  6 | 1004 |        8002 | 2021-08-02 19:48:01 |    90 |
|  7 | 1001 |        8002 | 2021-08-02 19:38:01 |    70 |
|  8 | 1004 |        8002 | 2021-08-02 19:48:01 |    90 |
|  9 | 1004 |        8002 | 2021-08-02 19:58:01 |    94 |
| 10 | 1004 |        8003 | 2021-08-02 19:38:01 |    70 |
| 11 | 1004 |        8003 | 2021-08-02 19:48:01 |    90 |
| 12 | 1004 |        8003 | 2021-08-01 19:38:01 |    80 |
+----+------+-------------+---------------------+-------+

请你找到高难度SQL试卷得分平均值大于80并且是7级的红名大佬,统计他们的2021年试卷总完成次数和题目总练习次数,只保留2021年有试卷完成记录的用户。
结果按试卷完成数升序,按题目练习数降序。
示例数据输出如下:
+------+----------+--------------+
| uid  | exam_cnt | question_cnt |
+------+----------+--------------+
| 1001 |        1 |            2 |
| 1003 |        2 |            0 |
+------+----------+--------------+

解释:用户1001100310041006满足高难度SQL试卷得分平均值大于80,但只有100110037级红名大佬;
1001完成了1次试卷1001,练习了2次题目;
1003完成了2次试卷90019002,未练习题目(因此计数为0)


 建表语句
drop table if exists examination_info,user_info,exam_record,practice_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 user_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int UNIQUE NOT NULL COMMENT '用户ID',
    `nick_name` varchar(64) COMMENT '昵称',
    achievement int COMMENT '成就值',
    level int COMMENT '用户等级',
    job varchar(32) COMMENT '职业方向',
    register_time datetime COMMENT '注册时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint 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 user_info(uid,`nick_name`,achievement,level,job,register_time) VALUES
  (1001, '牛客1号', 3100, 7, '算法', '2020-01-01 10:00:00'),
  (1002, '牛客2号', 2300, 7, '算法', '2020-01-01 10:00:00'),
  (1003, '牛客3号', 2500, 7, '算法', '2020-01-01 10:00:00'),
  (1004, '牛客4号', 1200, 5, '算法', '2020-01-01 10:00:00'),
  (1005, '牛客5号', 1600, 6, 'C++', '2020-01-01 10:00:00'),
  (1006, '牛客6号', 2000, 6, 'C++', '2020-01-01 10:00:00');

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 practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1002, 8001, '2021-09-02 19:30:01', 50),
(1002, 8001, '2021-09-02 19:20:01', 70),
(1002, 8002, '2021-09-02 19:38:01', 70),
(1004, 8001, '2021-08-02 19:38:01', 70),
(1004, 8002, '2021-08-02 19:48:01', 90),
(1001, 8002, '2021-08-02 19:38:01', 70),
(1004, 8002, '2021-08-02 19:48:01', 90),
(1004, 8002, '2021-08-02 19:58:01', 94),
(1004, 8003, '2021-08-02 19:38:01', 70),
(1004, 8003, '2021-08-02 19:48:01', 90),
(1004, 8003, '2021-08-01 19:38:01', 80);

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: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:40:01', 86),
(1003, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:51', 89),
(1004, 9001, '2021-09-01 19:01:01', '2021-09-01 19:30:01', 85),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:02', 85),
(1006, 9003, '2021-09-07 10:01:01', '2021-09-07 10:21:01', 84),
(1006, 9001, '2021-09-07 10:01:01', '2021-09-07 10:21:01', 80);


 答案
select er1.uid as uid,
       count(distinct er1.exam_id) as exam_cnt,
       count(distinct pr1.id) as question_cnt
from exam_record er1
left join practice_record pr1 on er1.uid = pr1.uid and year(er1.submit_time)=2021  and YEAR(pr1.submit_time)=2021
where er1.uid in (
    select er.uid
from user_info ui
left join exam_record er on ui.uid = er.uid
join examination_info ei on er.exam_id = ei.exam_id
where  ei.tag = 'SQL' and ui.level = 7 and difficulty = 'hard' and year(submit_time)=2021
group by ui.uid
having avg(er.score) >80)
group by er1.uid
order by exam_cnt , question_cnt desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第45张图片

SQL26 每个6/7级用户活跃情况

user_info表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第46张图片
examination_info表结构牛客刷题-SQL进阶挑战大总结(细节狂魔)_第47张图片
exam_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第48张图片
practice_record表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第49张图片

 题目描述
现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):
+----+------+------------+-------------+-------+--------+---------------------+
| id | uid  | nick_name  | achievement | level | job    | register_time       |
+----+------+------------+-------------+-------+--------+---------------------+
|  1 | 1001 | 牛客1|        3100 |     7 | 算法   | 2020-01-01 10:00:00 |
|  2 | 1002 | 牛客2|        2300 |     7 | 算法   | 2020-01-01 10:00:00 |
|  3 | 1003 | 牛客3|        2500 |     7 | 算法   | 2020-01-01 10:00:00 |
|  4 | 1004 | 牛客4|        1200 |     5 | 算法   | 2020-01-01 10:00:00 |
|  5 | 1005 | 牛客5|        1600 |     6 | C++    | 2020-01-01 10:00:00 |
|  6 | 1006 | 牛客6|        2000 |     6 | C++    | 2020-01-01 10:00:00 |
+----+------+------------+-------------+-------+--------+---------------------+

试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | hard       |       60 | 2021-09-01 06:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2021-09-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    81 |
|  2 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
|  3 | 1003 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    86 |
|  4 | 1003 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:51 |    89 |
|  5 | 1004 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:30:01 |    85 |
|  6 | 1005 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:02 |    85 |
|  7 | 1006 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:21:01 |    84 |
|  8 | 1006 |    9001 | 2021-09-07 10:01:01 | 2021-09-07 10:21:01 |    80 |
+----+------+---------+---------------------+---------------------+-------+

题目练习记录表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):
+----+------+-------------+---------------------+-------+
| id | uid  | question_id | submit_time         | score |
+----+------+-------------+---------------------+-------+
|  1 | 1001 |        8001 | 2021-08-02 11:41:01 |    60 |
|  2 | 1002 |        8001 | 2021-09-02 19:30:01 |    50 |
|  3 | 1002 |        8001 | 2021-09-02 19:20:01 |    70 |
|  4 | 1002 |        8002 | 2021-09-02 19:38:01 |    70 |
|  5 | 1004 |        8001 | 2021-08-02 19:38:01 |    70 |
|  6 | 1004 |        8002 | 2021-08-02 19:48:01 |    90 |
|  7 | 1001 |        8002 | 2021-08-02 19:38:01 |    70 |
|  8 | 1004 |        8002 | 2021-08-02 19:48:01 |    90 |
|  9 | 1004 |        8002 | 2021-08-02 19:58:01 |    94 |
| 10 | 1004 |        8003 | 2021-08-02 19:38:01 |    70 |
| 11 | 1004 |        8003 | 2021-08-02 19:48:01 |    90 |
| 12 | 1004 |        8003 | 2021-08-01 19:38:01 |    80 |
+----+------+-------------+---------------------+-------+

请统计每个6/7级用户总活跃月份数、2021年活跃天数、2021年试卷作答活跃天数、
2021年答题活跃天数,按照总活跃月份数、2021年活跃天数降序排序。由示例数据结果输出如下:
+------+-----------------+---------------+--------------------+------------------------+
| uid  | act_month_total | act_days_2021 | act_days_2021_exam | act_days_2021_question |
+------+-----------------+---------------+--------------------+------------------------+
| 1001 |               2 |             2 |                  1 |                      1 |
| 1002 |               1 |             2 |                  1 |                      1 |
| 1003 |               1 |             1 |                  1 |                      0 |
| 1005 |               1 |             1 |                  1 |                      0 |
| 1006 |               1 |             1 |                  1 |                      0 |
+------+-----------------+---------------+--------------------+------------------------+

解释:6/7级用户共有5个,其中10062021092021082020083个月活跃过,
2021年活跃的日期有202109072021080420210803202108024天,2021年在试卷作答区20210907活跃1天,在题目练习区活跃了3天。

 建表语句
drop table if exists examination_info,user_info,exam_record,practice_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 user_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int UNIQUE NOT NULL COMMENT '用户ID',
    `nick_name` varchar(64) COMMENT '昵称',
    achievement int COMMENT '成就值',
    level int COMMENT '用户等级',
    job varchar(32) COMMENT '职业方向',
    register_time datetime COMMENT '注册时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint 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 user_info(uid,`nick_name`,achievement,level,job,register_time) VALUES
  (1001, '牛客1号', 3100, 7, '算法', '2020-01-01 10:00:00'),
  (1002, '牛客2号', 2300, 7, '算法', '2020-01-01 10:00:00'),
  (1003, '牛客3号', 2500, 7, '算法', '2020-01-01 10:00:00'),
  (1004, '牛客4号', 1200, 5, '算法', '2020-01-01 10:00:00'),
  (1005, '牛客5号', 1600, 6, 'C++', '2020-01-01 10:00:00'),
  (1006, '牛客6号', 2600, 7, 'C++', '2020-01-01 10:00:00');

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

INSERT INTO practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1004, 8001, '2021-08-02 19:38:01', 70),
(1004, 8002, '2021-08-02 19:48:01', 90),
(1001, 8002, '2021-08-02 19:38:01', 70),
(1004, 8002, '2021-08-02 19:48:01', 90),
(1006, 8002, '2021-08-04 19:58:01', 94),
(1006, 8003, '2021-08-03 19:38:01', 70),
(1006, 8003, '2021-08-02 19:48:01', 90),
(1006, 8003, '2020-08-01 19:38:01', 80);

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:31:00', 78),
(1001, 9001, '2021-09-01 09:01:01', '2021-09-01 09:31:00', 81),
(1005, 9001, '2021-09-01 19:01:01', '2021-09-01 19:30:01', 85),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:02', 85),
(1006, 9003, '2021-09-07 10:01:01', '2021-09-07 10:21:59', 84),
(1006, 9001, '2021-09-07 10:01:01', '2021-09-07 10:21:01', 81),
(1002, 9001, '2020-09-01 13:01:01', '2020-09-01 13:41:01', 81),
(1005, 9001, '2021-09-01 14:01:01', null, null);

 答案
select t1.uid, count(distinct act_month) act_month_total,
count(distinct case when year(act_day)=2021 then act_day end) act_days_2021,
count(distinct case when left(tag,1)=9 and year(act_day)=2021 then act_day end) act_days_2021_exam,
count(distinct case when left(tag,1)=8 and year(act_day)=2021 then act_day end) act_days_2021_question
from user_info t1
left join (select uid ,
      date_format(start_time,'%Y%m') act_month,
      date_format(start_time,'%Y%m%d') act_day,
      exam_id tag
from exam_record
union all
select uid,
      date_format(submit_time,'%Y%m') act_month,
      date_format(submit_time,'%Y%m%d') act_day,
      question_id tag
from practice_record) t2
on t1.uid=t2.uid
where t1.uid in (select uid 
from user_info
where level in (6,7))
group by uid
order by act_month_total desc,act_days_2021 desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第50张图片

5.窗口函数

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第51张图片

5.1 专用窗口函数

SQL27 每类试卷得分前3名

examination_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第52张图片
exam_record表结构
在这里插入图片描述

 题目描述
现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2021-09-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    78 |
|  2 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    81 |
|  3 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
|  4 | 1003 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 |    86 |
|  5 | 1003 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:51 |    89 |
|  6 | 1004 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:30:01 |    85 |
|  7 | 1005 |    9003 | 2021-09-01 12:01:01 | 2021-09-01 12:31:02 |    85 |
|  8 | 1006 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:21:01 |    84 |
|  9 | 1003 |    9003 | 2021-09-08 12:01:01 | 2021-09-08 12:11:01 |    40 |
| 10 | 1003 |    9002 | 2021-09-01 14:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

找到每类试卷得分的前3名,如果两人最大分数相同,选择最小分数大者,如果还相同,选择uid大者。由示例数据结果输出如下:
+--------+------+----+
| tag    | uid  | rk |
+--------+------+----+
| SQL    | 1003 |  1 |
| SQL    | 1004 |  2 |
| SQL    | 1002 |  3 |
| 算法   | 1005 |  1 |
| 算法   | 1006 |  2 |
| 算法   | 1003 |  3 |
+--------+------+----+

解释:有作答得分记录的试卷tag有SQL和算法,SQL试卷用户1001100210031004有作答得分,
最高得分分别为81818985,最低得分分别为78818640,
因此先按最高得分排名再按最低得分排名取前三为100310041002。

 建表语句
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, 'SQL', '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:31:00', 78),
(1001, 9001, '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:40:01', 86),
(1003, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:51', 89),
(1004, 9001, '2021-09-01 19:01:01', '2021-09-01 19:30:01', 85),
(1005, 9003, '2021-09-01 12:01:01', '2021-09-01 12:31:02', 85),
(1006, 9003, '2021-09-07 10:01:01', '2021-09-07 10:21:01', 84),
(1003, 9003, '2021-09-08 12:01:01', '2021-09-08 12:11:01', 40),
(1003, 9002, '2021-09-01 14:01:01', null, null);


 答案
select tag,uid,rk
from (
    select tag, uid, rank() over (
        partition by tag order by tag,max(score) desc,min(score) desc,uid desc) as rk
    from exam_record er left join examination_info ei on er.exam_id = ei.exam_id
    group by tag,uid
) as t
where rk<=3;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第53张图片

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

examination_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第54张图片
exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第55张图片

 题目描述
现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2021-09-01 06:00:00 |
|  2 |    9002 | C++    | hard       |       60 | 2021-09-01 06:00:00 |
|  3 |    9003 | 算法   | medium     |       80 | 2021-09-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2021-09-01 09:01:01 | 2021-09-01 09:51:01 |    78 |
|  2 | 1001 |    9002 | 2021-09-01 09:01:01 | 2021-09-01 09:31:00 |    81 |
|  3 | 1002 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 |    81 |
|  4 | 1003 |    9001 | 2021-09-01 19:01:01 | 2021-09-01 19:59:01 |    86 |
|  5 | 1003 |    9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:51 |    89 |
|  6 | 1004 |    9002 | 2021-09-01 19:01:01 | 2021-09-01 19:30:01 |    85 |
|  7 | 1005 |    9001 | 2021-09-01 12:01:01 | 2021-09-01 12:31:02 |    85 |
|  8 | 1006 |    9001 | 2021-09-07 10:01:01 | 2021-09-07 10:12:01 |    84 |
|  9 | 1003 |    9001 | 2021-09-08 12:01:01 | 2021-09-08 12:11:01 |    40 |
| 10 | 1003 |    9002 | 2021-09-01 14:01:01 | NULL                |  NULL |
| 11 | 1005 |    9001 | 2021-09-01 14:01:01 | NULL                |  NULL |
| 12 | 1003 |    9003 | 2021-09-08 15:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

找到第二快和第二慢用时之差大于试卷时长的一半的试卷信息,按试卷ID降序排序。由示例数据结果输出如下:

解释:试卷9001被作答用时有50分钟、50分钟、301秒、11分钟、10分钟,
第二快和第二慢用时之差为50分钟-11分钟=39分钟,试卷时长为60分钟,
因此满足大于试卷时长一半的条件,输出试卷ID、时长、发布时间。


 建表语句
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);


 答案
SELECT distinct exam_id, duration, release_time
FROM 
(SELECT exam_id, duration, release_time,
 sum(case when rank1= 2 then costtime when rank2= 2 then -costtime else 0 end ) as sub
 from(
SELECT exam_id,duration, release_time,
TIMESTAMPDIFF(minute,start_time, submit_time) as costtime,
row_number() over (partition by exam_id order by TIMESTAMPDIFF(minute,start_time, submit_time) desc) as rank1,
row_number() over (partition by exam_id order by TIMESTAMPDIFF(minute,start_time, submit_time) asc)  as rank2
FROM exam_record
JOIN examination_info USING (exam_id)
 where submit_time is not null ) a 
 group by exam_id ) b 
 where sub * 2 >= duration
 order by exam_id desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第56张图片

SQL29 连续两次作答试卷的最大时间窗

exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第57张图片

 题目描述
现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1006 |    9003 | 2021-09-07 10:01:01 | 2021-09-07 10:21:02 |    84 |
|  2 | 1006 |    9001 | 2021-09-01 12:11:01 | 2021-09-01 12:31:01 |    89 |
|  3 | 1006 |    9002 | 2021-09-06 10:01:01 | 2021-09-06 10:21:01 |    81 |
|  4 | 1005 |    9002 | 2021-09-05 10:01:01 | 2021-09-05 10:21:01 |    81 |
|  5 | 1005 |    9001 | 2021-09-05 10:31:01 | 2021-09-05 10:51:01 |    81 |
+----+------+---------+---------------------+---------------------+-------+

请计算在2021年至少有两天作答过试卷的人中,计算该年连续两次作答试卷的最大时间窗days_window,
那么根据该年的历史规律他在days_window天里平均会做多少套试卷,按最大时间窗和平均做答试卷套数倒序排序。
由示例数据结果输出如下:
+------+-------------+--------------+
| uid  | days_window | avg_exam_cnt |
+------+-------------+--------------+
| 1006 |           6 |         2.57 |
+------+-------------+--------------+

解释:用户1006分别在202109012021090620210907作答过3次试卷,连续两次作答最大时间窗为6天(1号到6号),
他1号到7号这7天里共做了3张试卷,平均每天3/7=0.428571张,那么6天里平均会做0.428571*6=2.57张试卷(保留两位小数);
用户100520210905做了两张试卷,但是只有一天的作答记录,过滤掉。


 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1006, 9003, '2021-09-07 10:01:01', '2021-09-07 10:21:02', 84),
(1006, 9001, '2021-09-01 12:11:01', '2021-09-01 12:31:01', 89),
(1006, 9002, '2021-09-06 10:01:01', '2021-09-06 10:21:01', 81),
(1005, 9002, '2021-09-05 10:01:01', '2021-09-05 10:21:01', 81),
(1005, 9001, '2021-09-05 10:31:01', '2021-09-05 10:51:01', 81);

 答案

SELECT uid,max(day1)+1 days_window,
round((count(*)/(sum(day1)+1))*(max(day1)+1),2) avg_exam_cnt
from(
select uid,date1,lag1,datediff(date1,lag1) day1
from(
select uid,date(start_time) date1,
lag(date(start_time),1,date(start_time)) 
over(partition by uid order by start_time) lag1
from exam_record where uid in(
select uid from exam_record where year(start_time)=2021
group by uid having count(distinct date(start_time))>1) and year(start_time)=2021) a) b
group by uid
order by days_window desc,avg_exam_cnt desc;

备注:
按最大时间窗和平均做答试卷套数倒序排序,保留两位小数

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第58张图片

SQL30 近三个月未完成试卷数为0的用户完成情况

exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第59张图片

 题目描述
现有试卷作答记录表exam_record(uid:用户ID, exam_id:试卷ID, start_time:开始作答时间, 
submit_time:交卷时间,为空的话则代表未完成, score:得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1006 |    9003 | 2021-09-06 10:01:01 | 2021-09-06 10:21:02 |    84 |
|  2 | 1006 |    9001 | 2021-08-02 12:11:01 | 2021-08-02 12:31:01 |    89 |
|  3 | 1006 |    9002 | 2021-06-06 10:01:01 | 2021-06-06 10:21:01 |    81 |
|  4 | 1006 |    9002 | 2021-05-06 10:01:01 | 2021-05-06 10:21:01 |    81 |
|  5 | 1006 |    9001 | 2021-05-01 12:01:01 | NULL                |  NULL |
|  6 | 1001 |    9001 | 2021-09-05 10:31:01 | 2021-09-05 10:51:01 |    81 |
|  7 | 1001 |    9003 | 2021-08-01 09:01:01 | 2021-08-01 09:51:11 |    78 |
|  8 | 1001 |    9002 | 2021-07-01 09:01:01 | 2021-07-01 09:31:00 |    81 |
|  9 | 1001 |    9002 | 2021-07-01 12:01:01 | 2021-07-01 12:31:01 |    81 |
| 10 | 1001 |    9002 | 2021-07-01 12:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

找到每个人近三个有试卷作答记录的月份中没有试卷是未完成状态的用户的试卷作答完成数,按试卷完成数和用户ID降序排名。
由示例数据结果输出如下:
+------+-------------------+
| uid  | exam_complete_cnt |
+------+-------------------+
| 1006 |                 3 |
+------+-------------------+

解释:用户1006近三个有作答试卷的月份为202109202108202106,作答试卷数为3,全部完成;
用户1001近三个有作答试卷的月份为202109202108202107,作答试卷数为5,完成试卷数为4,
因为有未完成试卷,故过滤掉。


 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1006, 9003, '2021-09-06 10:01:01', '2021-09-06 10:21:02', 84),
(1006, 9001, '2021-08-02 12:11:01', '2021-08-02 12:31:01', 89),
(1006, 9002, '2021-06-06 10:01:01', '2021-06-06 10:21:01', 81),
(1006, 9002, '2021-05-06 10:01:01', '2021-05-06 10:21:01', 81),
(1006, 9001, '2021-05-01 12:01:01', null, null),
(1001, 9001, '2021-09-05 10:31:01', '2021-09-05 10:51:01', 81),
(1001, 9003, '2021-08-01 09:01:01', '2021-08-01 09:51:11', 78),
(1001, 9002, '2021-07-01 09:01:01', '2021-07-01 09:31:00', 81),
(1001, 9002, '2021-07-01 12:01:01', '2021-07-01 12:31:01', 81),
(1001, 9002, '2021-07-01 12:01:01', null, null);

select a.uid, count(a.start_time) as exam_complete_cnt
FROM
(
    select uid, start_time, submit_time,
    DENSE_RANK() over(partition by uid order by date_format(start_time, '%Y%m') desc) as time_rank
    from exam_record
) as a
where a.time_rank <= 3
group by a.uid
having count(a.start_time) = count(a.submit_time)
order by exam_complete_cnt desc, uid desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第60张图片

SQL31 未完成率较高的50%用户近三个月答卷情况

user_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第61张图片
examination_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第62张图片
exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第63张图片

 题目描述
现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):
+----+------+---------------+-------------+-------+--------+---------------------+
| id | uid  | nick_name     | achievement | level | job    | register_time       |
+----+------+---------------+-------------+-------+--------+---------------------+
|  1 | 1001 | 牛客1         |        3200 |     7 | 算法   | 2020-01-01 10:00:00 |
|  2 | 1002 | 牛客2|        2500 |     6 | 算法   | 2020-01-01 10:00:00 |
|  3 | 1003 | 牛客3号♂      |        2200 |     5 | 算法   | 2020-01-01 10:00:00 |
+----+------+---------------+-------------+-------+--------+---------------------+

试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | SQL    | hard       |       80 | 2020-01-01 10:00:00 |
|  3 |    9003 | 算法   | hard       |       80 | 2020-01-01 10:00:00 |
|  4 |    9004 | PYTHON | medium     |       70 | 2020-01-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-01 09:01:01 | 2020-01-01 09:21:59 |    90 |
|  2 | 1002 |    9001 | 2020-01-20 10:01:01 | NULL                |  NULL |
|  3 | 1002 |    9001 | 2020-02-01 12:11:01 | NULL                |  NULL |
|  4 | 1003 |    9001 | 2020-03-01 19:01:01 | NULL                |  NULL |
|  5 | 1001 |    9001 | 2020-03-01 12:01:01 | NULL                |  NULL |
|  6 | 1002 |    9001 | 2020-03-01 12:01:01 | 2020-03-01 12:41:01 |    90 |
|  7 | 1002 |    9001 | 2020-05-02 19:01:01 | 2020-05-02 19:32:00 |    90 |
|  8 | 1001 |    9002 | 2020-01-02 19:01:01 | 2020-01-02 19:59:01 |    69 |
|  9 | 1001 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:20:01 |    99 |
| 10 | 1002 |    9002 | 2020-02-02 12:01:01 | NULL                |  NULL |
| 11 | 1002 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:43:01 |    81 |
| 12 | 1002 |    9002 | 2020-03-02 12:11:01 | NULL                |  NULL |
| 13 | 1001 |    9001 | 2020-01-02 10:01:01 | 2020-01-02 10:31:01 |    89 |
| 14 | 1001 |    9002 | 2020-01-01 12:11:01 | NULL                |  NULL |
| 15 | 1002 |    9001 | 2020-01-01 18:01:01 | 2020-01-01 18:59:02 |    90 |
| 16 | 1002 |    9003 | 2020-05-06 12:01:01 | NULL                |  NULL |
| 17 | 1001 |    9002 | 2020-05-05 18:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

请统计SQL试卷上未完成率较高的50%用户中,6级和7级用户在有试卷作答记录的近三个月中,每个月的答卷数目和完成数目。按用户ID、月份升序排序。
由示例数据结果输出如下:
+------+-------------+-----------+--------------+
| uid  | start_month | total_cnt | complete_cnt |
+------+-------------+-----------+--------------+
| 1002 | 202002      |         3 |            1 |
| 1002 | 202003      |         2 |            1 |
| 1002 | 202005      |         2 |            1 |
+------+-------------+-----------+--------------+

解释:
100110021003分别排在1.00.50.0的位置,因此较高的50%用户(排位<=0.5)为100210031003不是6级或7级;
有试卷作答记录的近三个月为202005202003202002;
这三个月里1002的作答题数分别为322,完成数目分别为111。

 建表语句
drop table if exists examination_info,user_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 user_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int UNIQUE NOT NULL COMMENT '用户ID',
    `nick_name` varchar(64) COMMENT '昵称',
    achievement int COMMENT '成就值',
    level int COMMENT '用户等级',
    job varchar(32) COMMENT '职业方向',
    register_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 user_info(uid,`nick_name`,achievement,`level`,job,register_time) VALUES
  (1001, '牛客1', 3200, 7, '算法', '2020-01-01 10:00:00'),
  (1002, '牛客2号', 2500, 6, '算法', '2020-01-01 10:00:00'),
  (1003, '牛客3号♂', 2200, 5, '算法', '2020-01-01 10:00:00');

INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
  (9001, 'SQL', 'hard', 60, '2020-01-01 10:00:00'),
  (9002, 'SQL', 'hard', 80, '2020-01-01 10:00:00'),
  (9003, '算法', 'hard', 80, '2020-01-01 10:00:00'),
  (9004, 'PYTHON', 'medium', 70, '2020-01-01 10:00:00');
	
INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-01 09:01:01', '2020-01-01 09:21:59', 90),
(1002, 9001, '2020-01-20 10:01:01', null, null),
(1002, 9001, '2020-02-01 12:11:01', null, null),
(1003, 9001, '2020-03-01 19:01:01', null, null),
(1001, 9001, '2020-03-01 12:01:01', null, null),
(1002, 9001, '2020-03-01 12:01:01', '2020-03-01 12:41:01', 90),
(1002, 9001, '2020-05-02 19:01:01', '2020-05-02 19:32:00', 90),
(1001, 9002, '2020-01-02 19:01:01', '2020-01-02 19:59:01', 69),
(1001, 9002, '2020-02-02 12:01:01', '2020-02-02 12:20:01', 99),
(1002, 9002, '2020-02-02 12:01:01', null, null),
(1002, 9002, '2020-02-02 12:01:01', '2020-02-02 12:43:01', 81),
(1002, 9002, '2020-03-02 12:11:01', null, null),
(1001, 9001, '2020-01-02 10:01:01', '2020-01-02 10:31:01', 89),
(1001, 9002, '2020-01-01 12:11:01', null, null),
(1002, 9001, '2020-01-01 18:01:01', '2020-01-01 18:59:02', 90),
(1002, 9003, '2020-05-06 12:01:01', null, null),
(1001, 9002, '2020-05-05 18:01:01', null, null);

# 第一步,先找出未完成率前50%高的用户ID,注意这里需要的sql试卷
with rote_tab as 
(select t.uid,t.f_rote,row_number()over(order by t.f_rote desc,uid) as rank2
,count(t.uid)over(partition by t.tag)as cnt
from (select er.uid,ef.tag,(sum(if(submit_time is null,1,0))/count(start_time)) as f_rote
from exam_record er left join examination_info ef on ef.exam_id=er.exam_id where tag='SQL' group by uid ) t)

select  #第四步,分用户和月份进行数据统计;同时需要注意,统计的试卷数是所有类型的,不是之前仅有SQL类型
    uid
    ,start_month
    ,count(start_time) as total_cnt
    ,count(submit_time) as complete_cnt
from 
(
select # 第三步,利用窗口函数对每个用户的月份进行降序排序,以便找出最近的三个月;
    uid
    ,start_time
    ,submit_time
    ,date_format(start_time,'%Y%m') as start_month
    ,dense_rank()over(partition by uid order by date_format(start_time,'%Y%m') desc) as rank3
from exam_record 
where uid in 
    (select distinct er.uid
    from exam_record er left join user_info uf on uf.uid=er.uid
    where er.uid in (select uid from rote_tab where rank2<=round(cnt/2,0))
    and uf.level in (6,7))  # 第二步,进一步找出满足等级为6或7的用户ID
) t2
where rank3<=3
group by uid,start_month
order by uid,start_month;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第64张图片

SQL32 试卷完成数同比2020年的增长率及排名变化

examination_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第65张图片
exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第66张图片

 题目描述
现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | C++    | hard       |       80 | 2020-01-01 10:00:00 |
|  3 |    9003 | 算法   | hard       |       80 | 2020-01-01 10:00:00 |
|  4 |    9004 | PYTHON | medium     |       70 | 2020-01-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-08-02 10:01:01 | 2020-08-02 10:31:01 |    89 |
|  2 | 1002 |    9001 | 2020-04-01 18:01:01 | 2020-04-01 18:59:02 |    90 |
|  3 | 1001 |    9001 | 2020-04-01 09:01:01 | 2020-04-01 09:21:59 |    80 |
|  4 | 1002 |    9003 | 2021-01-20 10:01:01 | 2021-01-20 10:10:01 |    81 |
|  5 | 1002 |    9001 | 2021-03-02 19:01:01 | 2021-03-02 19:32:00 |    20 |
|  6 | 1001 |    9003 | 2021-04-02 19:01:01 | 2021-04-02 19:40:01 |    89 |
|  7 | 1004 |    9004 | 2020-05-02 12:01:01 | 2020-05-02 12:20:01 |    99 |
|  8 | 1003 |    9001 | 2021-05-02 12:01:01 | 2021-05-02 12:31:01 |    98 |
|  9 | 1001 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:20:01 |    99 |
| 10 | 1002 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:43:01 |    81 |
| 11 | 1001 |    9002 | 2020-01-02 19:01:01 | 2020-01-02 19:59:01 |    69 |
| 12 | 1001 |    9004 | 2021-09-02 12:11:01 | NULL                |  NULL |
| 13 | 1003 |    9001 | 2020-01-02 10:01:01 | 2020-01-02 10:31:01 |    89 |
| 14 | 1002 |    9004 | 2020-01-01 12:11:01 | 2020-01-01 12:31:01 |    83 |
| 15 | 1002 |    9003 | 2021-01-01 18:01:01 | 2021-01-01 18:59:02 |    90 |
| 16 | 1002 |    9002 | 2020-02-02 12:01:01 | NULL                |  NULL |
| 17 | 1002 |    9002 | 2020-03-02 12:11:01 | NULL                |  NULL |
| 18 | 1001 |    9002 | 2021-05-05 18:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

请计算2021年上半年各类试卷的做完次数相比2020年上半年同期的增长率(百分比格式,保留1位小数),
以及做完次数排名变化,按增长率和21年排名降序输出。
由示例数据结果输出如下:
+------+-------------+-------------+-------------+------------------+------------------+------------+
| tag  | exam_cnt_20 | exam_cnt_21 | growth_rate | exam_cnt_rank_20 | exam_cnt_rank_21 | rank_delta |
+------+-------------+-------------+-------------+------------------+------------------+------------+
| SQL  |           3 |           2 | -33.3%      |                1 |                2 |          1 |
+------+-------------+-------------+-------------+------------------+------------------+------------+


 建表语句
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, '2020-01-01 10:00:00'),
  (9002, 'C++', 'hard', 80, '2020-01-01 10:00:00'),
  (9003, '算法', 'hard', 80, '2020-01-01 10:00:00'),
  (9004, 'PYTHON', 'medium', 70, '2020-01-01 10:00:00');
	
INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-08-02 10:01:01', '2020-08-02 10:31:01', 89),
(1002, 9001, '2020-04-01 18:01:01', '2020-04-01 18:59:02', 90),
(1001, 9001, '2020-04-01 09:01:01', '2020-04-01 09:21:59', 80),
(1002, 9003, '2021-01-20 10:01:01', '2021-01-20 10:10:01', 81),
(1002, 9001, '2021-03-02 19:01:01', '2021-03-02 19:32:00', 20),
(1001, 9003, '2021-04-02 19:01:01', '2021-04-02 19:40:01', 89),
(1004, 9004, '2020-05-02 12:01:01', '2020-05-02 12:20:01', 99),
(1003, 9001, '2021-05-02 12:01:01', '2021-05-02 12:31:01', 98),
(1001, 9002, '2020-02-02 12:01:01', '2020-02-02 12:20:01', 99),
(1002, 9002, '2020-02-02 12:01:01', '2020-02-02 12:43:01', 81),
(1001, 9002, '2020-01-02 19:01:01', '2020-01-02 19:59:01', 69),
(1001, 9004, '2021-09-02 12:11:01', null, null),
(1003, 9001, '2020-01-02 10:01:01', '2020-01-02 10:31:01', 89),
(1002, 9004, '2020-01-01 12:11:01', '2020-01-01 12:31:01', 83),
(1002, 9003, '2021-01-01 18:01:01', '2021-01-01 18:59:02', 90),
(1002, 9002, '2020-02-02 12:01:01', null, null),
(1002, 9002, '2020-03-02 12:11:01', null, null),
(1001, 9002, '2021-05-05 18:01:01', null, null);

 答案
with info_2020 as (
select ei.tag, count(er.score) as exam_cnt ,rank() over(order by count(er.score) desc) as exam_cnt_rank
from exam_record as er
right join examination_info as ei
on er.exam_id=ei.exam_id
where year(er.start_time)=2020 and month(er.start_time)<=6
group by ei.tag
having count(er.score)>0),
info_2021 as (
select ei.tag, count(er.score) as exam_cnt ,rank() over(order by count(er.score) desc) as exam_cnt_rank
from exam_record as er
right join examination_info as ei
on er.exam_id=ei.exam_id
where year(er.start_time)=2021 and month(er.start_time)<=6
group by ei.tag
having count(er.score)>0),
exam_year_info as (
select i20.tag, i20.exam_cnt as exam_cnt_20, i21.exam_cnt as exam_cnt_21,
       i20.exam_cnt_rank as exam_cnt_rank_20, i21.exam_cnt_rank as exam_cnt_rank_21
from info_2020 as i20
join info_2021 as i21
on i20.tag=i21.tag)

select tag, exam_cnt_20, exam_cnt_21,
       concat(round((exam_cnt_21-exam_cnt_20)/exam_cnt_20*100, 1), '%') as growth_rate,
       exam_cnt_rank_20, exam_cnt_rank_21, (cast(exam_cnt_rank_21 as signed)-cast(exam_cnt_rank_20 as signed)) as rank_delta
from exam_year_info
order by growth_rate desc, exam_cnt_rank_21 desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第67张图片

5.2 聚合窗口函数

SQL33 对试卷得分做min-max归一化

examination_info 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第68张图片
exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第69张图片

 题目描述
现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间):
+----+---------+--------+------------+----------+---------------------+
| id | exam_id | tag    | difficulty | duration | release_time        |
+----+---------+--------+------------+----------+---------------------+
|  1 |    9001 | SQL    | hard       |       60 | 2020-01-01 10:00:00 |
|  2 |    9002 | C++    | hard       |       80 | 2020-01-01 10:00:00 |
|  3 |    9003 | 算法   | hard       |       80 | 2020-01-01 10:00:00 |
|  4 |    9004 | PYTHON | medium     |       70 | 2020-01-01 10:00:00 |
|  5 |    9005 | WEB    | hard       |       80 | 2020-01-01 10:00:00 |
|  6 |    9006 | PYTHON | hard       |       80 | 2020-01-01 10:00:00 |
|  7 |    9007 | web    | hard       |       80 | 2020-01-01 10:00:00 |
|  8 |    9008 | Web    | medium     |       70 | 2020-01-01 10:00:00 |
|  9 |    9009 | WEB    | medium     |       70 | 2020-01-01 10:00:00 |
| 10 |    9010 | SQL    | medium     |       70 | 2020-01-01 10:00:00 |
+----+---------+--------+------------+----------+---------------------+

试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-01 09:01:01 | 2020-01-01 09:21:59 |    90 |
|  2 | 1003 |    9002 | 2020-01-01 19:01:01 | 2020-01-01 19:30:01 |    75 |
|  3 | 1004 |    9002 | 2020-01-01 12:01:01 | 2020-01-01 12:11:01 |    60 |
|  4 | 1003 |    9002 | 2020-01-01 12:01:01 | 2020-01-01 12:41:01 |    90 |
|  5 | 1002 |    9002 | 2020-01-02 19:01:01 | 2020-01-02 19:32:00 |    90 |
|  6 | 1003 |    9001 | 2020-01-02 12:01:01 | 2020-01-02 12:31:01 |    68 |
|  7 | 1001 |    9002 | 2020-01-02 12:01:01 | 2020-01-02 12:43:01 |    81 |
|  8 | 1001 |    9005 | 2020-01-02 12:11:01 | NULL                |  NULL |
|  9 | 1001 |    9001 | 2020-01-02 10:01:01 | 2020-01-02 10:31:01 |    89 |
| 10 | 1002 |    9002 | 2020-01-01 12:11:01 | 2020-01-01 12:31:01 |    83 |
| 11 | 1002 |    9004 | 2021-09-06 12:01:01 | NULL                |  NULL |
| 12 | 1002 |    9002 | 2021-05-05 18:01:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

在物理学及统计学数据计算时,有个概念叫min-max标准化,也被称为离差标准化,是对原始数据的线性变换,使结果值映射到[0 - 1]之间。

请你将用户作答高难度试卷的得分在每份试卷作答记录内执行min-max归一化后缩放到[0,100]区间,并输出用户ID、试卷ID、归一化后分数平均值;
最后按照试卷ID升序、归一化分数降序输出。(注:得分区间默认为[0,100],
如果某个试卷作答记录中只有一个得分,那么无需使用公式,归一化并缩放后分数仍为原分数)。
由示例数据结果输出如下:
+------+---------+------+
| uid  | exam_id | sc1  |
+------+---------+------+
| 1001 |    9001 |   98 |
| 1003 |    9001 |    0 |
| 1002 |    9002 |   88 |
| 1003 |    9002 |   75 |
| 1001 |    9002 |   70 |
| 1004 |    9002 |    0 |
+------+---------+------+

解释:高难度试卷有900190029003;
作答了9001的记录有3条,分数分别为688990,按给定公式归一化后分数为:095100,
而后两个得分都是用户1001作答的,因此用户1001对试卷9001的新得分为(95+100)/298(只保留整数部分),
用户1003对于试卷9001的新得分为0。最后结果按照试卷ID升序、归一化分数降序输出。

 建表语句
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_bin;

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, '2020-01-01 10:00:00'),
  (9002, 'C++', 'hard', 80, '2020-01-01 10:00:00'),
  (9003, '算法', 'hard', 80, '2020-01-01 10:00:00'),
  (9004, 'PYTHON', 'medium', 70, '2020-01-01 10:00:00'),
  (9005, 'WEB', 'hard', 80, '2020-01-01 10:00:00'),
  (9006, 'PYTHON', 'hard', 80, '2020-01-01 10:00:00'),
  (9007, 'web', 'hard', 80, '2020-01-01 10:00:00'),
  (9008, 'Web', 'medium', 70, '2020-01-01 10:00:00'),
  (9009, 'WEB', 'medium', 70, '2020-01-01 10:00:00'),
  (9010, 'SQL', 'medium', 70, '2020-01-01 10:00:00');
	
INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-01 09:01:01', '2020-01-01 09:21:59', 90),
(1003, 9002, '2020-01-01 19:01:01', '2020-01-01 19:30:01', 75),
(1004, 9002, '2020-01-01 12:01:01', '2020-01-01 12:11:01', 60),
(1003, 9002, '2020-01-01 12:01:01', '2020-01-01 12:41:01', 90),
(1002, 9002, '2020-01-02 19:01:01', '2020-01-02 19:32:00', 90),
(1003, 9001, '2020-01-02 12:01:01', '2020-01-02 12:31:01', 68),
(1001, 9002, '2020-01-02 12:01:01', '2020-01-02 12:43:01', 81),
(1001, 9005, '2020-01-02 12:11:01', null, null),
(1001, 9001, '2020-01-02 10:01:01', '2020-01-02 10:31:01', 89),
(1002, 9002, '2020-01-01 12:11:01', '2020-01-01 12:31:01', 83),
(1002, 9004, '2021-09-06 12:01:01', null, null),
(1002, 9002, '2021-05-05 18:01:01', null, null);


 答案
select uid,exam_id,round(avg((score-min_score)/(max_score-min_score)*100)) sc1
from(
SELECT ex.uid,ex.exam_id,score,
max(score) over(partition by ex.exam_id ) max_score,
min(score) over(partition by ex.exam_id ) min_score
from exam_record ex join examination_info e on ex.exam_id=e.exam_id
where difficulty='hard' and score is not null) a
where max_score!=min_score group by uid,exam_id
union 
select uid,exam_id,score sc1
from(
SELECT ex.uid,ex.exam_id,score,
max(score) over(partition by ex.exam_id ) max_score,
min(score) over(partition by ex.exam_id ) min_score
from exam_record ex join examination_info e on ex.exam_id=e.exam_id
where difficulty='hard' and score is not null) b
where max_score=min_score
order by exam_id,sc1 desc;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第70张图片

SQL34 每份试卷每月作答数和截止当月的作答总数

exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第71张图片

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

请输出每份试卷每月作答数和截止当月的作答总数。
由示例数据结果输出如下:
+---------+-------------+-----------+--------------+
| exam_id | start_month | month_cnt | cum_exam_cnt |
+---------+-------------+-----------+--------------+
|    9001 | 202001      |         2 |            2 |
|    9001 | 202002      |         1 |            3 |
|    9001 | 202003      |         3 |            6 |
|    9001 | 202005      |         1 |            7 |
|    9002 | 202001      |         1 |            1 |
|    9002 | 202002      |         3 |            4 |
|    9002 | 202003      |         1 |            5 |
+---------+-------------+-----------+--------------+
解释:试卷90012020012020022020032020054个月有被作答记录,
每个月被作答数分别为2131,截止当月累积作答总数为2367。


 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-01 09:01:01', '2020-01-01 09:21:59', 90),
(1002, 9001, '2020-01-20 10:01:01', '2020-01-20 10:10:01', 89),
(1002, 9001, '2020-02-01 12:11:01', '2020-02-01 12:31:01', 83),
(1003, 9001, '2020-03-01 19:01:01', '2020-03-01 19:30:01', 75),
(1004, 9001, '2020-03-01 12:01:01', '2020-03-01 12:11:01', 60),
(1003, 9001, '2020-03-01 12:01:01', '2020-03-01 12:41:01', 90),
(1002, 9001, '2020-05-02 19:01:01', '2020-05-02 19:32:00', 90),
(1001, 9002, '2020-01-02 19:01:01', '2020-01-02 19:59:01', 69),
(1004, 9002, '2020-02-02 12:01:01', '2020-02-02 12:20:01', 99),
(1003, 9002, '2020-02-02 12:01:01', '2020-02-02 12:31:01', 68),
(1001, 9002, '2020-02-02 12:01:01', '2020-02-02 12:43:01', 81),
(1001, 9002, '2020-03-02 12:11:01', null, null);

 答案
SELECT exam_id, DATE_FORMAT(start_time,'%Y%m') start_month, 
COUNT(DATE_FORMAT(start_time,'%Y%m')) AS month_cnt, 
SUM(COUNT(DATE_FORMAT(start_time,'%Y%m'))) over (partition by exam_id order by DATE_FORMAT(start_time,'%Y%m'))
cum_exam_cnt
FROM exam_record
GROUP BY exam_id, start_month
ORDER BY exam_id, start_month;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第72张图片

SQL35 每月及截止当月的答题情况

exam_record 表结构
牛客刷题-SQL进阶挑战大总结(细节狂魔)_第73张图片

 题目描述
现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
+----+------+---------+---------------------+---------------------+-------+
| id | uid  | exam_id | start_time          | submit_time         | score |
+----+------+---------+---------------------+---------------------+-------+
|  1 | 1001 |    9001 | 2020-01-01 09:01:01 | 2020-01-01 09:21:59 |    90 |
|  2 | 1002 |    9001 | 2020-01-20 10:01:01 | 2020-01-20 10:10:01 |    89 |
|  3 | 1002 |    9001 | 2020-02-01 12:11:01 | 2020-02-01 12:31:01 |    83 |
|  4 | 1003 |    9001 | 2020-03-01 19:01:01 | 2020-03-01 19:30:01 |    75 |
|  5 | 1004 |    9001 | 2020-03-01 12:01:01 | 2020-03-01 12:11:01 |    60 |
|  6 | 1003 |    9001 | 2020-03-01 12:01:01 | 2020-03-01 12:41:01 |    90 |
|  7 | 1002 |    9001 | 2020-05-02 19:01:01 | 2020-05-02 19:32:00 |    90 |
|  8 | 1001 |    9002 | 2020-01-02 19:01:01 | 2020-01-02 19:59:01 |    69 |
|  9 | 1004 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:20:01 |    99 |
| 10 | 1003 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:31:01 |    68 |
| 11 | 1001 |    9002 | 2020-02-02 12:01:01 | 2020-02-02 12:43:01 |    81 |
| 12 | 1001 |    9002 | 2020-03-02 12:11:01 | NULL                |  NULL |
+----+------+---------+---------------------+---------------------+-------+

请输出自从有用户作答记录以来,每月的试卷作答记录中月活用户数、新增用户数、截止当月的单月最大新增用户数、截止当月的累积用户数。
结果按月份升序输出。由示例数据结果输出如下:
+--------+-----+--------------+------------------+------------+
| stime  | mau | month_add_uv | max_month_add_uv | cum_sum_uv |
+--------+-----+--------------+------------------+------------+
| 202001 |   2 |            2 |                2 |          2 |
| 202002 |   4 |            2 |                2 |          4 |
| 202003 |   3 |            0 |                2 |          4 |
| 202005 |   1 |            0 |                2 |          4 |
+--------+-----+--------------+------------------+------------+

 建表语句
drop table if exists exam_record;
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 exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2020-01-01 09:01:01', '2020-01-01 09:21:59', 90),
(1002, 9001, '2020-01-20 10:01:01', '2020-01-20 10:10:01', 89),
(1002, 9001, '2020-02-01 12:11:01', '2020-02-01 12:31:01', 83),
(1003, 9001, '2020-03-01 19:01:01', '2020-03-01 19:30:01', 75),
(1004, 9001, '2020-03-01 12:01:01', '2020-03-01 12:11:01', 60),
(1003, 9001, '2020-03-01 12:01:01', '2020-03-01 12:41:01', 90),
(1002, 9001, '2020-05-02 19:01:01', '2020-05-02 19:32:00', 90),
(1001, 9002, '2020-01-02 19:01:01', '2020-01-02 19:59:01', 69),
(1004, 9002, '2020-02-02 12:01:01', '2020-02-02 12:20:01', 99),
(1003, 9002, '2020-02-02 12:01:01', '2020-02-02 12:31:01', 68),
(1001, 9002, '2020-02-02 12:01:01', '2020-02-02 12:43:01', 81),
(1001, 9002, '2020-03-02 12:11:01', null, null);


 答案
SELECT stime,mau,if(month_add is not null,month_add,0) as month_add_uv,
max(if(month_add is not null, month_add,0)) over (order by stime) as max_month_add_uv,
sum(if(month_add is not null, month_add,0)) over (order by stime) as cum_sum_uv
FROM
      (SELECT stime, count(distinct uid) as mau FROM 
         (SELECT uid,DATE_FORMAT(start_time,'%Y%m') as stime FROM exam_record) a 
         GROUP BY stime) c 
      LEFT JOIN 
      (SELECT ntime, count(distinct uid) as month_add FROM
         (SELECT uid,min(DATE_FORMAT(start_time,'%Y%m')) as ntime from exam_record GROUP BY uid) b 
          GROUP BY ntime) d 
      ON c.stime=d.ntime;

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第74张图片

体系化学习SQL,请到经典高频面试题库,参加实训,提高你的SQL技能吧~

https://www.nowcoder.com/link/pc_csdncpt_itbd_sql

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第75张图片

牛客刷题-SQL进阶挑战大总结(细节狂魔)_第76张图片

你可能感兴趣的:(如何成为SQL高手,sql,数据库,dba)