1. 0级用户高难度试卷的平均用时和平均得分

现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间),数据如下:

id uid nick_name achievement level job register_time
1 1001 牛客1号 10 0 算法 2020-01-01 10:00:00
2 1002 牛客2号 2100 6 算法 2020-01-01 10:00:00

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

试卷作答记录表,数据如下

id uid exam_id start_time submit_time score
1 1001 9001 2020-01-02 09:01:01 2020-01-02 09:21:59 80
2 1001 9001 2021-05-02 10:01:01 (NULL) (NULL)
3 1001 9002 2021-02-02 19:01:01 2021-02-02 19:30:01 87
4 1001 9001 2021-06-02 19:01:01 2021-06-02 19:32:00 20
5 1001 9002 2021-09-05 19:01:01 2021-09-05 19:40:01 89
6 1001 9002 2021-09-01 12:01:01 (NULL) (NULL)
7 1002 9002 2021-05-05 18:01:01 2021-05-05 18:59:02 90

请输出每个0级用户所有的高难度试卷考试平均用时和平均得分,未完成的默认试卷最大考试时长和0分处理。由示例数据结果输出如下:

uid avg_score avg_time_took
1001 33 36.7

解释:0级用户有1001,高难度试卷有9001,1001作答9001的记录有3条,分别用时20分钟、未完成(试卷时长60分钟)、30分钟(未满31分钟),分别得分为80分、未完成(0分处理)、20分。因此他的平均用时为110/3=36.7(保留一位小数),平均得分为33分(取整)

示例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号', 10, 0, '算法', '2020-01-01 10:00:00'),(1002, '牛客2号', 2100, 6, '算法', '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', 'easy', 60, '2020-01-01 10:00:00'),(9004, '算法', 'medium', 80, '2020-01-01 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:59', 80),
(1001, 9001, '2021-05-02 10:01:01', null, null),
(1001, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1001, 9001, '2021-06-02 19:01:01', '2021-06-02 19:32:00', 20),
(1001, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1002, 9002, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90);
输出

1001|33|36.7

题解
写法一:select uid,
round(avg(if(score is not null,score,0)),0)avg_score,
round(avg(if(submit_time is not null,timestampdiff(minute,start_time,submit_time),duration)),1)avg_time_tookfrom examination_info
inner join exam_record
using (exam_id)
inner join user_info
using (uid)
where difficulty='hard' and  `level`=0
group by uid写法二:
select uid,round(avg(new_score), 0) as avg_score,round(avg(cost_time), 1) as avg_time_took
from(select e_r.uid as uid,if(score is not null, score, 0) as new_score,if(submit_time is not null, timestampdiff(minute, start_time, submit_time), duration) as cost_timefrom exam_record e_r join examination_info e_ion e_r.exam_id = e_i.exam_idjoin user_info u_ion e_r.uid = u_i.uidwhere level = 0and difficulty = 'hard') new_table
group by uid

2. 筛选限定昵称成就值活跃日期的用户

现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):

id uid nick_name achievement level job register_time
1 1001 牛客1号 1000 2 算法 2020-01-01 10:00:00
2 1002 牛客2号 1200 3 算法 2020-01-01 10:00:00
3 1003 进击的3号 2200 5 算法 2020-01-01 10:00:00
4 1004 牛客4号 2500 6 算法 2020-01-01 10:00:00
5 1005 牛客5号 3000 7 C++ 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-02 09:01:01 2020-01-02 09:21:59 80
3 1001 9002 2021-02-02 19:01:01 2021-02-02 19:30:01 87
2 1001 9001 2021-05-02 10:01:01 (NULL) (NULL)
4 1001 9001 2021-06-02 19:01:01 2021-06-02 19:32:00 20
6 1001 9002 2021-09-01 12:01:01 (NULL) (NULL)
5 1001 9002 2021-09-05 19:01:01 2021-09-05 19:40:01 89
11 1002 9001 2020-01-01 12:01:01 2020-01-01 12:31:01 81
12 1002 9002 2020-02-01 12:01:01 2020-02-01 12:31:01 82
13 1002 9002 2020-02-02 12:11:01 2020-02-02 12:31:01 83
7 1002 9002 2021-05-05 18:01:01 2021-05-05 18:59:02 90
16 1002 9001 2021-09-06 12:01:01 2021-09-06 12:21:01 80
17 1002 9001 2021-09-06 12:01:01 (NULL) (NULL)
18 1002 9001 2021-09-07 12:01:01 (NULL) (NULL)
8 1003 9003 2021-02-06 12:01:01 (NULL) (NULL)
9 1003 9001 2021-09-07 10:01:01 2021-09-07 10:31:01 89
10 1004 9002 2021-08-06 12:01:01 (NULL) (NULL)
14 1005 9001 2021-02-01 11:01:01 2021-02-01 11:31:01 84
15 1006 9001 2021-02-01 11:01:01 2021-02-01 11:31:01 84

题目练习记录表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 8002 2021-09-01 19:38:01 80

请找到昵称以『牛客』开头『号』结尾、成就值在1200~2500之间,且最近一次活跃(答题或作答试卷)在2021年9月的用户信息。

由示例数据结果输出如下:

uid nick_name achievement
1002 牛客2号 1200

解释:昵称以『牛客』开头『号』结尾且成就值在1200~2500之间的有1002、1004;

1002最近一次试卷区活跃为2021年9月,最近一次题目区活跃为2021年9月;1004最近一次试卷区活跃为2021年8月,题目区未活跃。

因此最终满足条件的只有1002。

示例1
drop table if exists user_info,exam_record,practice_record;
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号', 1000, 2, '算法', '2020-01-01 10:00:00'),(1002, '牛客2号', 1200, 3, '算法', '2020-01-01 10:00:00'),(1003, '进击的3号', 2200, 5, '算法', '2020-01-01 10:00:00'),(1004, '牛客4号', 2500, 6, '算法', '2020-01-01 10:00:00'),(1005, '牛客5号', 3000, 7, 'C++', '2020-01-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),
(1003, 8002, '2021-09-01 19:38:01', 80);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:59', 80),
(1001, 9001, '2021-05-02 10:01:01', null, null),
(1001, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1001, 9001, '2021-06-02 19:01:01', '2021-06-02 19:32:00', 20),
(1001, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1002, 9002, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90),
(1003, 9003, '2021-02-06 12:01:01', null, null),
(1003, 9001, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 89),
(1004, 9002, '2021-08-06 12:01:01', null, null),
(1002, 9001, '2020-01-01 12:01:01', '2020-01-01 12:31:01', 81),
(1002, 9002, '2020-02-01 12:01:01', '2020-02-01 12:31:01', 82),
(1002, 9002, '2020-02-02 12:11:01', '2020-02-02 12:31:01', 83),
(1005, 9001, '2021-02-01 11:01:01', '2021-02-01 11:31:01', 84),
(1006, 9001, '2021-02-01 11:01:01', '2021-02-01 11:31:01', 84),
(1002, 9001, '2021-09-06 12:01:01', '2021-09-06 12:21:01', 80),
(1002, 9001, '2021-09-06 12:01:01', null, null),
(1002, 9001, '2021-09-07 12:01:01', null, null);
输出

1002|牛客2号|1200

思路
1.昵称以『牛客』开头『号』结尾:WHERE nick_name LIKE "牛客%号"
2.成就值在1200~2500之间:achievement BETWEEN 1200 AND 2500
3.最近一次活跃(答题或作答试卷)在2021年9月:
4.生成用户每次活跃月份:
试卷区活跃情况:SELECT distinct uid, DATE_FORMAT(start_time, "%Y%m") as active_month
练习区活跃情况:SELECT distinct uid, DATE_FORMAT(submit_time, "%Y%m") as active_month
合并活跃情况:UNION
5.按用户分组:GROUP BY uid
6.筛选最近一次活跃月份:HAVING MAX(active_month)="202109"
题解
     select uid,nick_name,achievementfrom user_info where achievement between 1200 and 2500 and nick_name like '牛客%号'and uid in(select uidfrom (select distinct uid,max(date_format(start_time,"%Y-%m"))over(partition by uid order by date_format(start_time,"%Y-%m") desc)max_monthfrom exam_recordunionselect distinct uid,max(date_format(submit_time,"%Y-%m"))over(partition by uid order by date_format(submit_time,"%Y-%m") desc)max_monthfrom practice_record)tgroup by uidhaving max(max_month)='2021-09');

3. 筛选昵称规则和试卷规则的作答记录

现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):

id uid nick_name achievement level job register_time
1 1001 牛客1号 1900 2 算法 2020-01-01 10:00:00
2 1002 牛客2号 1200 3 算法 2020-01-01 10:00:00
3 1003 牛客3号♂ 2200 5 算法 2020-01-01 10:00:00
4 1004 牛客4号 2500 6 算法 2020-01-01 10:00:00
5 1005 牛客555号 2000 7 C++ 2020-01-01 10:00:00
6 1006 666666 3000 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 C++ hard 60 2020-01-01 10:00:00
2 9002 c# hard 80 2020-01-01 10:00:00
3 9003 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-02 09:01:01 2020-01-02 09:21:59 80
2 1001 9001 2021-05-02 10:01:01 (NULL) (NULL)
4 1001 9001 2021-06-02 19:01:01 2021-06-02 19:32:00 20
3 1001 9002 2021-02-02 19:01:01 2021-02-02 19:30:01 87
5 1001 9002 2021-09-05 19:01:01 2021-09-05 19:40:01 89
6 1001 9002 2021-09-01 12:01:01 (NULL) (NULL)
11 1002 9001 2020-01-01 12:01:01 2020-01-01 12:31:01 81
16 1002 9001 2021-09-06 12:01:01 2021-09-06 12:21:01 80
17 1002 9001 2021-09-06 12:01:01 (NULL) (NULL)
18 1002 9001 2021-09-07 12:01:01 (NULL) (NULL)
7 1002 9002 2021-05-05 18:01:01 2021-05-05 18:59:02 90
12 1002 9002 2020-02-01 12:01:01 2020-02-01 12:31:01 82
13 1002 9002 2020-02-02 12:11:01 2020-02-02 12:31:01 83
9 1003 9001 2021-09-07 10:01:01 2021-09-07 10:31:01 89
8 1003 9003 2021-02-06 12:01:01 (NULL) (NULL)
10 1004 9002 2021-08-06 12:01:01 (NULL) (NULL)
14 1005 9001 2021-02-01 11:01:01 2021-02-01 11:31:01 84
15 1006 9001 2021-02-01 11:01:01 2021-09-01 11:31:01 84

找到昵称以"牛客"+纯数字+"号"或者纯数字组成的用户对于字母c开头的试卷类别(如C,C++,c#等)的已完成的试卷ID和平均得分,按用户ID、平均分升序排序。由示例数据结果输出如下:

uid exam_id avg_score
1002 9001 81
1002 9002 85
1005 9001 84
1006 9001 84

解释:昵称满足条件的用户有1002、1004、1005、1006;

c开头的试卷有9001、9002;

满足上述条件的作答记录中,1002完成9001的得分有81、80,平均分为81(80.5取整四舍五入得81);

1002完成9002的得分有90、82、83,平均分为85;

示例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', 1900, 2, '算法', '2020-01-01 10:00:00'),(1002, '牛客2号', 1200, 3, '算法', '2020-01-01 10:00:00'),(1003, '牛客3号♂', 2200, 5, '算法', '2020-01-01 10:00:00'),(1004, '牛客4号', 2500, 6, '算法', '2020-01-01 10:00:00'),(1005, '牛客555号', 2000, 7, 'C++', '2020-01-01 10:00:00'),(1006, '666666', 3000, 6, 'C++', '2020-01-01 10:00:00');INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES(9001, 'C++', 'hard', 60, '2020-01-01 10:00:00'),(9002, 'c#', 'hard', 80, '2020-01-01 10:00:00'),(9003, '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-02 09:01:01', '2020-01-02 09:21:59', 80),
(1001, 9001, '2021-05-02 10:01:01', null, null),
(1001, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1001, 9001, '2021-06-02 19:01:01', '2021-06-02 19:32:00', 20),
(1001, 9002, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 89),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1002, 9002, '2021-05-05 18:01:01', '2021-05-05 18:59:02', 90),
(1003, 9003, '2021-02-06 12:01:01', null, null),
(1003, 9001, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 89),
(1004, 9002, '2021-08-06 12:01:01', null, null),
(1002, 9001, '2020-01-01 12:01:01', '2020-01-01 12:31:01', 81),
(1002, 9002, '2020-02-01 12:01:01', '2020-02-01 12:31:01', 82),
(1002, 9002, '2020-02-02 12:11:01', '2020-02-02 12:31:01', 83),
(1005, 9001, '2021-02-01 11:01:01', '2021-02-01 11:31:01', 84),
(1006, 9001, '2021-09-01 11:01:01', '2021-09-01 11:31:01', 84),
(1002, 9001, '2021-09-06 12:01:01', '2021-09-06 12:21:01', 80),
(1002, 9001, '2021-09-06 12:01:01', null, null),
(1002, 9001, '2021-09-07 12:01:01', null, null);
输出

1002|9001|81
1002|9002|85
1005|9001|84
1006|9001|84

题解
写法一:
select t.uid,t.exam_id,t.avg_scorefrom user_infoinner join (select uid,exam_id,round(avg(score),0) avg_scorefrom examination_infoinner join exam_recordusing(exam_id)where tag like 'C%' and score is not nullgroup by uid,exam_id)tusing (uid)
where nick_name like'牛客%' and nick_name like'%号'and (nick_name REGEXP '[^0-9.]')=1 or (nick_name REGEXP '[^0-9.]')!=1
order by uid,avg_score写法二:
SELECT uid, exam_id, ROUND(AVG(score),0) avg_score
FROM exam_record
WHERE uid IN (SELECT uid FROM user_info WHERE nick_name RLIKE "^牛客[0-9]+号$" OR nick_name RLIKE "^[0-9]+$")AND exam_id IN (SELECT exam_id FROM examination_infoWHERE tag RLIKE "^[cC]") AND score IS NOT NULL
GROUP BY uid, exam_id
ORDER BY uid,avg_score;写法三:
SELECT uid, exam_id, ROUND(AVG(score), 0) as avg_score
FROM exam_record
WHERE score IS NOT NULLand exam_id in (SELECT exam_idFROM examination_infoWHERE tag REGEXP "^[cC]")and uid in (SELECT uid FROM user_infoWHERE nick_name REGEXP "^牛客[0-9]+号$"OR nick_name REGEXP "^[0-9]+$")
GROUP BY uid, exam_id
ORDER BY uid, avg_score;
拓展 (like、rlike、regexp的用法及区别)
正则表达式
1、字符^
意义:表示匹配的字符必须在最前边。
例如:^A不匹配“an A”中的‘A’,但匹配“An A”中最前面的‘A’。2、字符$
意义:与^类似,匹配最末的字符。
例如:t$不匹配“eater”中的‘t’,但匹配“eat”中的‘t’。3、字符[0-9]
意义:字符列表,匹配列出中的任一个字符。你可以通过连字符-指出字符范围。
例如:[abc]跟[a-c]一样。它们匹配“brisket”中的‘b’和“ache”中的‘c’。4、字符+
意义:匹配+号前面的字符1次及以上。等价于{1,}。
例如:^A不匹配“an A”中的‘A’,但匹配“An A”中最前面的‘A’。示例1
select  ("c"REGEXP "^[cC]")一、like
MySQL提供了两个通配符供 LIKE 使用:百分号%和下划线_。百分号(%)通配符匹配任何零个或多个字符的字符串。
下划线(_)通配符匹配任何单个字符。例如:
s%匹配任何字符串以s字符开头,例如sun和six。
se_匹配以 se 开头,后面跟着的任何一个字符,如see和sea二、rlike操作符
1、模糊查询字段中包含某关键字的信息。
如:查询所有包含“希望”的信息:select * from student where name rlike '希望'
2、模糊查询字段中以某关键字开头的信息。
如:查询所有以“大”开头的信息:select * from student where name not rlike '^大'
3、模糊查询字段中以某关键字结尾的信息。
如:查询所有以“大”结尾的信息:select * from student where name not rlike '大$'
4、模糊匹配或关系,又称分支条件。
如:查询出字段中包含“幸福,幸运,幸好,幸亏”的信息:
select * from student where name  rlike '幸福|幸运|幸好|幸亏'三、regexp操作符
MySQL允许您使用REGEXP运算符在SQL语句中匹配模式。
以下说明REGEXP WHER子句中运算符的语法:SELECT column_list
FROMtable_name
WHEREstring_column REGEXP pattern;此语句执行 string_column对pattern的模式匹配。
如果string_column匹配的值为WHERE子句中pattern的表达式返回true,否则返回false。
如果string_column或者pattern是NULL,结果是NULL。
除了REGEXP运算符之外,您还可以使用RLIKE运算符,它是运算符的同义词REGEXP。
REGEXP运营商的否定形式是NOT REGEXP。示例:
SELECT productname
FROMproducts
WHEREproductname REGEXP '^(A|B|C)'
ORDER BY productname;

4. 根据指定记录是否存在输出不同情况

现有用户信息表user_info(uid用户ID,nick_name昵称, achievement成就值, level等级, job职业方向, register_time注册时间):

id uid nick_name achievement level job register_time
1 1001 牛客1号 19 0 算法 2020-01-01 10:00:00
2 1002 牛客2号 1200 3 算法 2020-01-01 10:00:00
3 1003 进击的3号 22 0 算法 2020-01-01 10:00:00
4 1004 牛客4号 25 0 算法 2020-01-01 10:00:00
5 1005 牛客555号 2000 7 C++ 2020-01-01 10:00:00
6 1006 666666 3000 6 C++ 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-02 09:01:01 2020-01-02 09:21:59 80
2 1001 9001 2021-05-02 10:01:01 (NULL) (NULL)
3 1001 9002 2021-02-02 19:01:01 2021-02-02 19:30:01 87
4 1001 9002 2021-09-01 12:01:01 (NULL) (NULL)
5 1001 9003 2021-09-02 12:01:01 (NULL) (NULL)
6 1001 9004 2021-09-03 12:01:01 (NULL) (NULL)
7 1002 9001 2020-01-01 12:01:01 2020-01-01 12:31:01 99
8 1002 9003 2020-02-01 12:01:01 2020-02-01 12:31:01 82
9 1002 9003 2020-02-02 12:11:01 (NULL) (NULL)
10 1002 9002 2021-05-05 18:01:01 (NULL) (NULL)
11 1002 9001 2021-09-06 12:01:01 (NULL) (NULL)
12 1003 9003 2021-02-06 12:01:01 (NULL) (NULL)
13 1003 9001 2021-09-07 10:01:01 2021-09-07 10:31:01 89

请你筛选表中的数据,当有任意一个0级用户未完成试卷数大于2时,输出每个0级用户的试卷未完成数和未完成率(保留3位小数);若不存在这样的用户,则输出所有有作答记录的用户的这两个指标。结果按未完成率升序排序。

由示例数据结果输出如下:

uid incomplete_cnt incomplete_rate
1004 0 0.000
1003 1 0.500
1001 4 0.667

解释:0级用户有1001、1003、1004;他们作答试卷数和未完成数分别为:6:4、2:1、0:0;

存在1001这个0级用户未完成试卷数大于2,因此输出这三个用户的未完成数和未完成率(1004未作答过试卷,未完成率默认填0,保留3位小数后是0.000);

结果按照未完成率升序排序。

附:如果1001不满足『未完成试卷数大于2』,则需要输出1001、1002、1003的这两个指标,因为试卷作答记录表里只有这三个用户的作答记录。

示例1
drop table if exists user_info,exam_record;
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', 19, 0, '算法', '2020-01-01 10:00:00'),(1002, '牛客2号', 1200, 3, '算法', '2020-01-01 10:00:00'),(1003, '牛客3号♂', 22, 0, '算法', '2020-01-01 10:00:00'),(1004, '牛客4号', 25, 0, '算法', '2020-01-01 10:00:00'),(1005, '牛客555号', 2000, 7, 'C++', '2020-01-01 10:00:00'),(1006, '666666', 3000, 6, 'C++', '2020-01-01 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:59', 80),
(1001, 9001, '2021-05-02 10:01:01', null, null),
(1001, 9002, '2021-02-02 19:01:01', '2021-02-02 19:30:01', 87),
(1001, 9002, '2021-09-01 12:01:01', null, null),
(1001, 9003, '2021-09-02 12:01:01', null, null),
(1001, 9004, '2021-09-03 12:01:01', null, null),
(1002, 9001, '2020-01-01 12:01:01', '2020-01-01 12:31:01', 99),
(1002, 9003, '2020-02-01 12:01:01', '2020-02-01 12:31:01', 82),
(1002, 9003, '2020-02-02 12:11:01', null, null),
(1002, 9002, '2021-05-05 18:01:01', null, null),
(1002, 9001, '2021-09-06 12:01:01', null, null),
(1003, 9003, '2021-02-06 12:01:01', null, null),
(1003, 9001, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 89);
输出

1004|0|0.000
1003|1|0.500
1001|4|0.667

思路
1.统计每个用户的等级、未完成数、未完成率和总作答数,生成临时表 t_tag_count:
2.右连接试卷作答表和用户信息表:exam_record RIGHT JOIN user_info USING(uid)
3.按用户分组:GROUP BY uid
统计未完成数:COUNT(start_time) - COUNT(submit_time) as incomplete_cnt
统计未完成率:IFNULL(1 - COUNT(submit_time) / COUNT(start_time), 0) as incomplete_rate
保留3位小数:ROUND(x, 3)
统计总作答数:COUNT(start_time) as total_cnt
4.当存在0级用户未完成试卷数大于2时:
筛选存在性条件:WHERE EXISTS (SELECT uid FROM t_tag_count WHERE level = 0 AND incomplete_cnt > 2)
5.输出每个0级用户的试卷未完成数和未完成率:
筛选0级用户:level = 0
SELECT uid, incomplete_cnt, incomplete_rate
当不存在0级用户未完成试卷数大于2时:
筛选存在性条件:WHERE NOT EXISTS (SELECT uid FROM t_tag_count WHERE level = 0 AND incomplete_cnt > 2)
6.合并上述结果,条件互斥,so只可能有一个结果集:UNION ALL
题解
方式一:
with t_temp as (
select uid,`level`,
count(start_time)-count(score) incomplete_cnt, -- 未完成数
round(ifnull(1-count(score)/count(start_time),0),3)incomplete_rate, -- 未完成率
count(start_time) total_count -- 作答数
from user_info
left join exam_record
using(uid)
group by uid
)
select uid,incomplete_cnt,incomplete_rate
from t_temp
where exists(select uid from t_temp where `level`=0 and incomplete_cnt>2
)and `level`=0
union all
select uid,incomplete_cnt,incomplete_rate
from t_temp
where not exists(select uid from t_temp where `level`=0 and incomplete_cnt>2
)and `total_count`>0
ORDER BY incomplete_rate;方式二:
select uid,incomplete_cnt,incomplete_rate
from
(select uid,`level`,flag,incomplete_cnt,incomplete_rate,last_value(incomplete_cnt)over(order by level desc,incomplete_cnt ascrows between unbounded preceding and unbounded following) tag_countfrom(selectinfo.uid,`level`,record.uid as flag,-- 用户表没有的uidcount(start_time)-count(score) incomplete_cnt, -- 未完成数round(ifnull(1-count(score)/count(start_time),0),3)incomplete_rate -- 未完成率from exam_record recordright join user_info infoon record.uid=info.uidgroup by info.uid)t
)t1
where (level=0 and tag_count>2) or (tag_count<=2 and flag is not null)
order by incomplete_rate asc
拓展 LAST_VALUE() 函数

FIRST_VALUE()函数是一个窗口函数,允许您选择有序行集中的最前一行。(同理)

LAST_VALUE()函数是一个窗口函数,允许您选择有序行集中的最后一行。

以下显示了LAST_VALUE()函数的语法:

LAST_VALUE (expression) OVER ([partition_clause][order_clause][frame_clause]
)

LAST_VALUE()函数返回expression有序行集的最后一行的值。

OVER有三个子句:partition_clauseorder_clause,和frame_clause

partition_clause

partition_clause语法如下:

PARTITION BY expr1, expr2, ...

PARTITION BY子句分配结果集成由一个或多个表达式指定多个分区expr1expr2LAST_VALUE()函数被独立地施加到每个分区。

order_clause

order_clause语法如下:

ORDER BY  expr1 [ASC|DESC],...

ORDER BY子句指定LAST_VALUE()函数运行的分区中行的逻辑顺序。

frame_clause

frame_clause定义了所述当前分区的所述子集LAST_VALUE()函数应用。有关更多详细信息frame_clause,请查看窗口功能教程。


MySQL LAST_VALUE() 函数示例

让我们设置一个示例表进行演示。

以下是创建overtime表并将数据填充到表中的脚本。

CREATE TABLE overtime (employee_name VARCHAR(50) NOT NULL,department VARCHAR(50) NOT NULL,hours INT NOT NULL,PRIMARY KEY (employee_name , department)
);INSERT INTO overtime(employee_name, department, hours)
VALUES('Diane Murphy','Accounting',37),
('Mary Patterson','Accounting',74),
('Jeff Firrelli','Accounting',40),
('William Patterson','Finance',58),
('Gerard Bondur','Finance',47),
('Anthony Bow','Finance',66),
('Leslie Jennings','IT',90),
('Leslie Thompson','IT',88),
('Julie Firrelli','Sales',81),
('Steve Patterson','Sales',29),
('Foon Yue Tseng','Sales',65),
('George Vanauf','Marketing',89),
('Loui Bondur','Marketing',49),
('Gerard Hernandez','Marketing',66),
('Pamela Castillo','SCM',96),
('Larry Bott','SCM',100),
('Barry Jones','SCM',65);
mysql> select * from overtime;
+-------------------+------------+-------+
| employee_name     | department | hours |
+-------------------+------------+-------+
| Anthony Bow       | Finance    |    66 |
| Barry Jones       | SCM        |    65 |
| Diane Murphy      | Accounting |    37 |
| Foon Yue Tseng    | Sales      |    65 |
| George Vanauf     | Marketing  |    89 |
| Gerard Bondur     | Finance    |    47 |
| Gerard Hernandez  | Marketing  |    66 |
| Jeff Firrelli     | Accounting |    40 |
| Julie Firrelli    | Sales      |    81 |
| Larry Bott        | SCM        |   100 |
| Leslie Jennings   | IT         |    90 |
| Leslie Thompson   | IT         |    88 |
| Loui Bondur       | Marketing  |    49 |
| Mary Patterson    | Accounting |    74 |
| Pamela Castillo   | SCM        |    96 |
| Steve Patterson   | Sales      |    29 |
| William Patterson | Finance    |    58 |
+-------------------+------------+-------+
17 rows in set (0.01 sec)
1)MySQL LAST_VALUE()在整个查询结果示例中

以下语句获取员工姓名,加班时间和加班时间最长的员工:

SELECTemployee_name,hours,LAST_VALUE(employee_name) OVER (ORDER BY hoursRANGE BETWEENUNBOUNDED PRECEDING ANDUNBOUNDED FOLLOWING) highest_overtime_employee
FROMovertime;

输出是:

+-------------------+-------+---------------------------+
| employee_name     | hours | highest_overtime_employee |
+-------------------+-------+---------------------------+
| Steve Patterson   |    29 | Larry Bott                |
| Diane Murphy      |    37 | Larry Bott                |
| Jeff Firrelli     |    40 | Larry Bott                |
| Gerard Bondur     |    47 | Larry Bott                |
| Loui Bondur       |    49 | Larry Bott                |
| William Patterson |    58 | Larry Bott                |
| Barry Jones       |    65 | Larry Bott                |
| Foon Yue Tseng    |    65 | Larry Bott                |
| Anthony Bow       |    66 | Larry Bott                |
| Gerard Hernandez  |    66 | Larry Bott                |
| Mary Patterson    |    74 | Larry Bott                |
| Julie Firrelli    |    81 | Larry Bott                |
| Leslie Thompson   |    88 | Larry Bott                |
| George Vanauf     |    89 | Larry Bott                |
| Leslie Jennings   |    90 | Larry Bott                |
| Pamela Castillo   |    96 | Larry Bott                |
| Larry Bott        |   100 | Larry Bott                |
+-------------------+-------+------------------------

在此示例中,ORDER BY子句将结果集中行的逻辑顺序指定为从低到高的小时。

默认帧规范如下:

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

这意味着框架从第一行开始,到结果集的当前行结束。

因此,为了获得加班时间最长的员工,我们将框架规格更改为以下内容:

RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

这表示框架从第一行开始,到结果集的最后一行结束。

2)MySQL LAST_VALUE()上的分区示例

以下语句查找每个部门加班时间最长的员工:

SELECTemployee_name,department,hours,LAST_VALUE(employee_name) OVER (PARTITION BY departmentORDER BY hoursRANGE BETWEENUNBOUNDED PRECEDING ANDUNBOUNDED FOLLOWING) most_overtime_employee
FROMovertime;

下图显示了输出:

+-------------------+------------+-------+------------------------+
| employee_name     | department | hours | most_overtime_employee |
+-------------------+------------+-------+------------------------+
| Diane Murphy      | Accounting |    37 | Mary Patterson         |
| Jeff Firrelli     | Accounting |    40 | Mary Patterson         |
| Mary Patterson    | Accounting |    74 | Mary Patterson         |
| Gerard Bondur     | Finance    |    47 | Anthony Bow            |
| William Patterson | Finance    |    58 | Anthony Bow            |
| Anthony Bow       | Finance    |    66 | Anthony Bow            |
| Leslie Thompson   | IT         |    88 | Leslie Jennings        |
| Leslie Jennings   | IT         |    90 | Leslie Jennings        |
| Loui Bondur       | Marketing  |    49 | George Vanauf          |
| Gerard Hernandez  | Marketing  |    66 | George Vanauf          |
| George Vanauf     | Marketing  |    89 | George Vanauf          |
| Steve Patterson   | Sales      |    29 | Julie Firrelli         |
| Foon Yue Tseng    | Sales      |    65 | Julie Firrelli         |
| Julie Firrelli    | Sales      |    81 | Julie Firrelli         |
| Barry Jones       | SCM        |    65 | Larry Bott             |
| Pamela Castillo   | SCM        |    96 | Larry Bott             |
| Larry Bott        | SCM        |   100 | Larry Bott             |
+-------------------+------------+-------+------------------------+
17 rows in set (0.02 sec)

在这个例子中,首先,PARTITION BY子句按部门划分了员工。然后,ORDER BY子句通过加班从低到高命令每个部门的员工。

在这种情况下,帧规范是整个分区。结果,LAST_VALUE()函数选择了每个分区中的最后一行,分区是加班时间最高的员工。

在本教程中,您学习了如何使用MySQL LAST_VALUE()函数获取有序行集中的最后一行。

SQL(进阶实战05)相关推荐

  1. 【SQL开发实战技巧】系列(十八):数据仓库中时间类型操作(进阶)INTERVAL、EXTRACT以及如何确定一年是否为闰年及周的计算

    系列文章目录 [SQL开发实战技巧]系列(一):关于SQL不得不说的那些事 [SQL开发实战技巧]系列(二):简单单表查询 [SQL开发实战技巧]系列(三):SQL排序的那些事 [SQL开发实战技巧] ...

  2. 【SQL开发实战技巧】系列(十九):数据仓库中时间类型操作(进阶)如何一个SQL打印当月或一年的日历?如何确定某月内第一个和最后—个周内某天的日期?

    系列文章目录 [SQL开发实战技巧]系列(一):关于SQL不得不说的那些事 [SQL开发实战技巧]系列(二):简单单表查询 [SQL开发实战技巧]系列(三):SQL排序的那些事 [SQL开发实战技巧] ...

  3. 【SQL开发实战技巧】系列(二十一):数据仓库中时间类型操作(进阶)识别重叠的日期范围,按指定10分钟时间间隔汇总数据

    系列文章目录 [SQL开发实战技巧]系列(一):关于SQL不得不说的那些事 [SQL开发实战技巧]系列(二):简单单表查询 [SQL开发实战技巧]系列(三):SQL排序的那些事 [SQL开发实战技巧] ...

  4. .NET深入实战系列—Linq to Sql进阶

    .NET深入实战系列-Linq to Sql进阶 最近在写代码的过程中用到了Linq查询,在查找资料的过程中发现网上的资料千奇百怪,于是自己整理了一些关于Linq中容易让人困惑的地方. 本文全部代码基 ...

  5. 聊天机器人落地及进阶实战 | 公开课速记

    嘉宾 | 邵浩 编辑 | suiling 来源 | AI科技大本营在线公开课 近年来,聊天机器人技术及产品得到了快速的发展.聊天机器人作为人工智能技术的杀手级应用,发展得如火如荼,各种智能硬件层出不穷 ...

  6. MySQL的进阶实战篇

    关联文章: MySQL的初次见面礼基础实战篇 MySQL的进阶实战篇 本篇上一篇博文MySQL的初次见面礼基础实战篇的延续,是mysql的进阶内容的记录,本篇主要知识点如下: 进阶实战篇 进阶实战篇 ...

  7. 【SQL进阶】03.执行计划之旅1 - 初探

    听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. S ...

  8. oracle dba入门线路图--记某培训公司的ORACLE DBA技能进阶实战大纲

    博主注:给oracle dba入门者的一点建议,个人也收藏一个. ORACLE DBA技能进阶实战 一.新手入行须知 首先了解DBA这个职业,再决定要不要做DBA:如果要做DBA,怎么才能做好DBA: ...

  9. mysql数据生产数据分析_基于MySQL玩转SQL数据分析课程 互联网数据分析师-SQL数据分析实战视频教程...

    基于MySQL玩转SQL数据分析课程 互联网数据分析师-SQL数据分析实战视频教程 课程目录 (1)SQL与数Ju分析;目录中文件数:23个 (1) 开课-课时3SQL与数Ju库的价值.flv (2) ...

最新文章

  1. Facebook AI新研究:可解释神经元或许会阻碍DNN的学习
  2. 谷歌人工智能野心:从“下围棋”开始走向商用赚钱
  3. linux中 用户管理命令,Linux中的常用用户和用户组管理命令
  4. 云服务器虚拟主机区别,云服务器和虚拟主机的区别
  5. 中汽中心软件测评中心与紫光国微达成芯片认证合作
  6. OA办公系统需要专业的系统管理员
  7. linux调度器(九)——调度器的配置参数
  8. html 重复执行函数,javascript延时重复执行函数 lLoopRun.js
  9. 计算机键盘如何打字课件,电脑键盘打字入门基础.ppt
  10. Video标签的常用属性操作
  11. calcbusiness使用教程_Calc Business
  12. 在美团投放广告的优势、展现形式介绍!
  13. Tab页面知识整理及其方法分析
  14. 业务流程管理工具的概览和比较分析
  15. 哪些浏览器支持html5?
  16. 最近电平接近 NLM 模块化多电平变换器matlab/simulink仿真模型
  17. KBEngine warring项目源码阅读(一) 项目简介和注册
  18. GEE学习:查询遥感影像空间分辨率
  19. item_search - 根据关键词取虾皮(Shopee)商品列表
  20. python编写交互界面查分,Python实现CET查分的方法 -电脑资料

热门文章

  1. 第三章 C语言运算符,表达式,序列点,类型转换
  2. 手把手教你玩转OpenWRT路由器系统,视频教程合集
  3. 赛效:如何在线更改图片格式 图片格式在线转换方法介绍
  4. Pandas操作总结
  5. python编辑器geany_另外一款编辑器 Geany
  6. 算法设计与分析基础 第六章谜题
  7. [注]微信公众号的运营推广总结方案(持续更新)
  8. STM32下载程序至SRAM——基于正点原子精英STM32F103ZET6开发板
  9. AMD首款5纳米PC处理器锐龙7000亮相,频率首破5GHz大关,单核性能提升15%
  10. CAD中怎么设置CAD标注样式?CAD看图软件教程