牛客网SQL刷题一

以下为非技术快速入门题目

SQL35 浙大不同难度题目的正确率

  • 题目
drop table if exists `user_profile`;
drop table if  exists `question_practice_detail`;
drop table if  exists `question_detail`;
CREATE TABLE `user_profile` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`gender` varchar(14) NOT NULL,
`age` int ,
`university` varchar(32) NOT NULL,
`gpa` float,
`active_days_within_30` int ,
`question_cnt` int ,
`answer_cnt` int 
);
CREATE TABLE `question_practice_detail` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`question_id`int NOT NULL,
`result` varchar(32) NOT NULL,
`date` date NOT NULL
);
CREATE TABLE `question_detail` (
`id` int NOT NULL,
`question_id`int NOT NULL,
`difficult_level` varchar(32) NOT NULL
);

INSERT INTO user_profile VALUES(1,2138,'male',21,'北京大学',3.4,7,2,12);
INSERT INTO user_profile VALUES(2,3214,'male',null,'复旦大学',4.0,15,5,25);
INSERT INTO user_profile VALUES(3,6543,'female',20,'北京大学',3.2,12,3,30);
INSERT INTO user_profile VALUES(4,2315,'female',23,'浙江大学',3.6,5,1,2);
INSERT INTO user_profile VALUES(5,5432,'male',25,'山东大学',3.8,20,15,70);
INSERT INTO user_profile VALUES(6,2131,'male',28,'山东大学',3.3,15,7,13);
INSERT INTO user_profile VALUES(7,4321,'male',28,'复旦大学',3.6,9,6,52);
INSERT INTO question_practice_detail VALUES(1,2138,111,'wrong','2021-05-03');
INSERT INTO question_practice_detail VALUES(2,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(3,3214,113,'wrong','2021-06-15');
INSERT INTO question_practice_detail VALUES(4,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(5,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(6,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(7,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(8,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(9,3214,113,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(10,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(11,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(12,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(13,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(14,3214,112,'wrong','2021-08-16');
INSERT INTO question_practice_detail VALUES(15,3214,113,'wrong','2021-08-18');
INSERT INTO question_practice_detail VALUES(16,6543,111,'right','2021-08-13');
INSERT INTO question_detail VALUES(1,111,'hard');
INSERT INTO question_detail VALUES(2,112,'medium');
INSERT INTO question_detail VALUES(3,113,'easy');
INSERT INTO question_detail VALUES(4,115,'easy');
INSERT INTO question_detail VALUES(5,116,'medium');
INSERT INTO question_detail VALUES(6,117,'easy');
  • 解法
-- 正确率:avg(正确算1/全部)
select difficult_level, round(avg(if(result='right',1,0)),4) correct_rate
from question_practice_detail qpd 
join question_detail qd on qpd.question_id =qd.question_id
join user_profile u on qpd.device_id =u.device_id 
where u.university='浙江大学'
group by difficult_level
order by correct_rate asc

-- 正确率:正确的次数/全部次数* 100% 
-- count 会忽略null值 
select difficult_level, round(count(if(result='right',1,null))/count(*),4) correct_rate
from question_practice_detail qpd 
join question_detail qd on qpd.question_id =qd.question_id
join user_profile u on qpd.device_id =u.device_id 
where u.university='浙江大学'
group by difficult_level
order by correct_rate asc

-- 也可以用sum
select difficult_level, round(sum(if(result='right',1,0))/count(*),4) correct_rate
from question_practice_detail qpd 
join question_detail qd on qpd.question_id =qd.question_id
join user_profile u on qpd.device_id =u.device_id 
where u.university='浙江大学'
group by difficult_level
order by correct_rate asc

SQL34 统计复旦用户8月练题情况

  • 题目
drop table if exists `user_profile`;
drop table if  exists `question_practice_detail`;
drop table if  exists `question_detail`;
CREATE TABLE `user_profile` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`gender` varchar(14) NOT NULL,
`age` int ,
`university` varchar(32) NOT NULL,
`gpa` float,
`active_days_within_30` int ,
`question_cnt` int ,
`answer_cnt` int 
);
CREATE TABLE `question_practice_detail` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`question_id`int NOT NULL,
`result` varchar(32) NOT NULL,
`date` date NOT NULL
);
CREATE TABLE `question_detail` (
`id` int NOT NULL,
`question_id`int NOT NULL,
`difficult_level` varchar(32) NOT NULL
);

INSERT INTO user_profile VALUES(1,2138,'male',21,'北京大学',3.4,7,2,12);
INSERT INTO user_profile VALUES(2,3214,'male',null,'复旦大学',4.0,15,5,25);
INSERT INTO user_profile VALUES(3,6543,'female',20,'北京大学',3.2,12,3,30);
INSERT INTO user_profile VALUES(4,2315,'female',23,'浙江大学',3.6,5,1,2);
INSERT INTO user_profile VALUES(5,5432,'male',25,'山东大学',3.8,20,15,70);
INSERT INTO user_profile VALUES(6,2131,'male',28,'山东大学',3.3,15,7,13);
INSERT INTO user_profile VALUES(7,4321,'male',28,'复旦大学',3.6,9,6,52);
INSERT INTO question_practice_detail VALUES(1,2138,111,'wrong','2021-05-03');
INSERT INTO question_practice_detail VALUES(2,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(3,3214,113,'wrong','2021-06-15');
INSERT INTO question_practice_detail VALUES(4,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(5,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(6,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(7,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(8,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(9,3214,113,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(10,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(11,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(12,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(13,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(14,3214,112,'wrong','2021-08-16');
INSERT INTO question_practice_detail VALUES(15,3214,113,'wrong','2021-08-18');
INSERT INTO question_practice_detail VALUES(16,6543,111,'right','2021-08-13');
INSERT INTO question_detail VALUES(1,111,'hard');
INSERT INTO question_detail VALUES(2,112,'medium');
INSERT INTO question_detail VALUES(3,113,'easy');
INSERT INTO question_detail VALUES(4,115,'easy');
INSERT INTO question_detail VALUES(5,116,'medium');
INSERT INTO question_detail VALUES(6,117,'easy');
  • 解法
-- 复旦用户:以用户为准一个都不能漏
-- 8月:如果用在where中,会将8月没有进行答题的用户过滤掉,不符合提议,所以8月需要作为连接条件
select u.device_id,university,count(qpd.result) question_cnt, count(if(result='right',1,null)) right_question_cnt
from 
user_profile u 
left join question_practice_detail qpd on u.device_id =qpd.device_id and date_format(date,'%Y%m')='202108'
where u.university ='复旦大学'
group by u.device_id 

-- 需要注意不要将没答题的用户漏掉了
select u.device_id,university,qpd.result question_cnt, if(result='right',1,null) right_question_cnt
from 
user_profile u 
left join question_practice_detail qpd on u.device_id =qpd.device_id and date_format(date,'%Y%m')='202108'
where u.university ='复旦大学'

-- 或者左外的时候,把右表空记录也取出来
select u.device_id,university,qpd.result question_cnt, if(result='right',1,null) right_question_cnt
from 
user_profile u 
left join question_practice_detail qpd on u.device_id =qpd.device_id 
where u.university ='复旦大学'  and (date_format(date,'%Y%m')='202108' or date is null)

device_id|university|question_cnt|right_question_cnt|
---------+----------+------------+------------------+
     3214|复旦大学      |wrong       |                  |
     3214|复旦大学      |wrong       |                  |
     3214|复旦大学      |wrong       |                  |
     4321|复旦大学      |            |                  |

SQL33 找出每个学校GPA最低的同学

  • 题目
drop table if exists user_profile;
CREATE TABLE `user_profile` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`gender` varchar(14) NOT NULL,
`age` int ,
`university` varchar(32) NOT NULL,
`gpa` float,
`active_days_within_30` int ,
`question_cnt` int ,
`answer_cnt` int 
);
INSERT INTO user_profile VALUES(1,2138,'male',21,'北京大学',3.4,7,2,12);
INSERT INTO user_profile VALUES(2,3214,'male',null,'复旦大学',4.0,15,5,25);
INSERT INTO user_profile VALUES(3,6543,'female',20,'北京大学',3.2,12,3,30);
INSERT INTO user_profile VALUES(4,2315,'female',23,'浙江大学',3.6,5,1,2);
INSERT INTO user_profile VALUES(5,5432,'male',25,'山东大学',3.8,20,15,70);
INSERT INTO user_profile VALUES(6,2131,'male',28,'山东大学',3.3,15,7,13);
INSERT INTO user_profile VALUES(7,4321,'male',28,'复旦大学',3.6,9,6,52);
  • 解法
-- 每个topN
select device_id, university, round(gpa,4 ) gpa from (
  select device_id, university, gpa,
  rank() over(partition by university order by gpa asc) rk
  from user_profile
) tmp
where rk=1
order by university asc

-- 1.将每个学生的gpa和最小的ga比较,
-- 2.将外层的device_id所在university放入子查询中,
-- 3.意味着每个学生都都要查询他所在学校的最小值
-- 4.如果等于最小值,返回值
select device_id, university, gpa
from user_profile u
where u.gpa=(
  select min(gpa) from user_profile u2
    where u2.university=u.university
  )
order by university asc

-- 1.构造一张只有每个学校最低分的虚表
-- 2.从学生全表中和虚表关联,连接条件是学校和最低分 
select device_id, u.university, gpa 
from user_profile u
join (
  select university,min(gpa) min_gpa 
  from user_profile 
  group by university
  ) u2 on u.university=u2.university and u.gpa=u2.min_gpa
order by university asc

SQL31 提取博客URL中的用户名

  • 题目
drop table if exists user_submit;
CREATE TABLE `user_submit` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`profile` varchar(100) NOT NULL,
`blog_url` varchar(100) NOT NULL
);
INSERT INTO user_submit VALUES(1,2138,'180cm,75kg,27,male','http:/url/bisdgboy777');
INSERT INTO user_submit VALUES(1,3214,'165cm,45kg,26,female','http:/url/dkittycc');
INSERT INTO user_submit VALUES(1,6543,'178cm,65kg,25,male','http:/url/tigaer');
INSERT INTO user_submit VALUES(1,4321,'171cm,55kg,23,female','http:/url/uhsksd');
INSERT INTO user_submit VALUES(1,2131,'168cm,45kg,22,female','http:/url/sysdney');
  • 解法
1、LOCATE(substr , str ):返回子串 substr 在字符串 str 中第一次出现的位置,如果字符substr在字符串str中不存在,则返回0;
2、POSITION(substr  IN str ):返回子串 substr 在字符串 str 中第一次出现的位置,如果字符substr在字符串str中不存在,与LOCATE函数作用相同;
3、LEFT(str, length):从左边开始截取str,length是截取的长度;
4、RIGHT(str, length):从右边开始截取str,length是截取的长度;
5、SUBSTRING_INDEX(str  ,substr  ,n):返回字符substr在str中第n次出现位置之前的字符串;
6、SUBSTRING(str  ,n ,m):返回字符串str从第n个字符截取到第m个字符;
7、REPLACE(str, n, m):将字符串str中的n字符替换成m字符;
8、LENGTH(str):计算字符串str的长度。 

-- 通过下标取数据
select device_id,substring_index(blog_url,'/',-1) user_name
from user_submit

-- 截取从pos位置开始到最后的所有str字符串
-- SUBSTR (str, pos, len)
select device_id,substr(blog_url,11) user_name
from user_submit

-- 替换取
select device_id,replace(blog_url,'http:/url/','') user_name
from user_submit

-- 通过裁剪取:trim('被裁减的内容' from 字段)
select device_id ,trim('http:/url/' from blog_url) as user_name 
from user_submit

SQL29 计算用户的平均次日留存率

  • 题目
drop table if exists `user_profile`;
drop table if  exists `question_practice_detail`;
drop table if  exists `question_detail`;
CREATE TABLE `user_profile` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`gender` varchar(14) NOT NULL,
`age` int ,
`university` varchar(32) NOT NULL,
`gpa` float,
`active_days_within_30` int ,
`question_cnt` int ,
`answer_cnt` int 
);
CREATE TABLE `question_practice_detail` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`question_id`int NOT NULL,
`result` varchar(32) NOT NULL,
`date` date NOT NULL
);
CREATE TABLE `question_detail` (
`id` int NOT NULL,
`question_id`int NOT NULL,
`difficult_level` varchar(32) NOT NULL
);

INSERT INTO user_profile VALUES(1,2138,'male',21,'北京大学',3.4,7,2,12);
INSERT INTO user_profile VALUES(2,3214,'male',null,'复旦大学',4.0,15,5,25);
INSERT INTO user_profile VALUES(3,6543,'female',20,'北京大学',3.2,12,3,30);
INSERT INTO user_profile VALUES(4,2315,'female',23,'浙江大学',3.6,5,1,2);
INSERT INTO user_profile VALUES(5,5432,'male',25,'山东大学',3.8,20,15,70);
INSERT INTO user_profile VALUES(6,2131,'male',28,'山东大学',3.3,15,7,13);
INSERT INTO user_profile VALUES(7,4321,'male',28,'复旦大学',3.6,9,6,52);
INSERT INTO question_practice_detail VALUES(1,2138,111,'wrong','2021-05-03');
INSERT INTO question_practice_detail VALUES(2,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(3,3214,113,'wrong','2021-06-15');
INSERT INTO question_practice_detail VALUES(4,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(5,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(6,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(7,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(8,3214,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(9,3214,113,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(10,6543,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(11,2315,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(12,2315,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(13,2315,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(14,3214,112,'wrong','2021-08-16');
INSERT INTO question_practice_detail VALUES(15,3214,113,'wrong','2021-08-18');
INSERT INTO question_practice_detail VALUES(16,6543,111,'right','2021-08-13');
INSERT INTO question_detail VALUES(1,111,'hard');
INSERT INTO question_detail VALUES(2,112,'medium');
INSERT INTO question_detail VALUES(3,113,'easy');
INSERT INTO question_detail VALUES(4,115,'easy');
INSERT INTO question_detail VALUES(5,116,'medium');
INSERT INTO question_detail VALUES(6,117,'easy');
  • 解法
select count(if(datediff(date2,date1)=1,1,null))/count(*)
from (
  select device_id,date date1,
  lead(date,1) over (partition by device_id order by date) date2
  from
  (select distinct device_id,date from question_practice_detail) tmp
) t 

select count(datediff)/count(*)
from (
  select device_id,date,
  if(datediff(lead(date,1) over (partition by device_id order by date),date)=1,1,null) datediff
  from
  (select distinct device_id,date from question_practice_detail) tmp
) t 

select avg(if(date2,1,0))
from (
  select device_id,date,
  if(datediff(lead(date,1) over (partition by device_id order by date),date)=1,1,null) date2
  from
  (select distinct device_id,date from question_practice_detail) tmp
) t 

select device_id,date,
if(datediff(date,lag(date,1) over (partition by device_id order by date))=1,1,null) date2
from
(select distinct device_id,date from question_practice_detail) tmp


-- 左外连多加一天,右表有值表示隔天又登录,null表示隔天没登录
-- 用data_add/data_sub
select count(date2)/count(*) 
-- select avg(if(date2,1,0))
from (
  select distinct q1.device_id,q2.date date2,q1.date date1
  from
  question_practice_detail q1
  left join question_practice_detail q2 on q1.device_id=q2.device_id and date_add(q1.date,interval 1 day)=q2.date
) t

-- 也可以用datediff
select count(date2)/count(*) 
-- select avg(if(date2,1,0))
from (
  select distinct q1.device_id,q2.date date2,q1.date date1
  from
  question_practice_detail q1
  left join question_practice_detail q2 on q1.device_id=q2.device_id and datediff(q1.date,q2.date)=1
) t

以下为SQL进阶挑战题目

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

  • 题目
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);
  • 解法
-- 去掉一个最高分,去掉一个最低分,去掉null,求平均值
with tmp as (
select tag,difficulty,er.score
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where ei.tag='SQL'
and ei.difficulty ='hard'
and score is not null )
select tag,difficulty,round((sum(score)-min(score)-max(score))/(count(*)-2),1)  from tmp
group by tag,difficulty

-- min/max + 开窗
select tag,difficulty,round((sum(score) - max(max_score)-min(min_score))/(count(*)-2),1) from (
select tag,difficulty,er.score,
max(score) over(partition by tag,difficulty order by score) max_score,
min(score) over(partition by tag,difficulty order by score) min_score
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where ei.tag='SQL'
and ei.difficulty ='hard'
and score is not null )t
group by tag,difficulty

-- 没说按照那一个进行分组或者分区,就是全表求最值
select tag,difficulty,round((sum(score) - max(score)-min(score))/(count(*)-2),1)
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where ei.tag='SQL'
and ei.difficulty ='hard'
and score is not null 

-- 条件中放min/max
-- not或者不等中可能会过滤掉相同的极值
select tag,difficulty,round(avg(score),1)
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where ei.tag='SQL'
and ei.difficulty ='hard'
and score not in (select max(score) from exam_record)
and score not in (select min(score) from exam_record)

-- rank + 开窗
select tag,difficulty,round(avg(score),1) from (
select tag,difficulty,er.score,
rank() over(partition by tag,difficulty order by score desc) rk_max,
rank() over(partition by tag,difficulty order by score asc) rk_min
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where ei.tag='SQL'
and ei.difficulty ='hard'
and score is not null )t where rk_max!=1 and rk_min!=1

SQL15 统计作答次数

  • 题目
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);
  • 解法
- count(distinct 字段 and 字段 is not null)
SELECT
COUNT(start_time) as total_pv, #有开始作答时间可视为一次作答
COUNT(submit_time) as complete_pv,#有交卷时间可视为完成一次作答
count(distinct exam_id and score is not null)
as complete_exam_cnt#将试卷去重,同时将筛选完成的试卷
from exam_record;

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

  • 题目
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) from exam_record er
join examination_info ei on er.exam_id =ei.exam_id
where 
score >=
(
  select avg(score)
  from exam_record er
  left join examination_info ei on er.exam_id =ei.exam_id where tag='SQL'
)
and tag='SQL'

with e as(
  select er.score
  from exam_record er
  left join examination_info ei
  on er.exam_id=ei.exam_id
  where ei.tag='SQL'
  and er.score is not null
)
select 
min(score) min_score_over_avg
from e
where score>=(select avg(score) from e)

select min(score) from (
  select er.score,
  avg(score) over () avg_score
  from exam_record er
  left join examination_info ei
  on er.exam_id=ei.exam_id
  where ei.tag='SQL'
  and er.score is not null
  )t
where score >avg_score
  

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

  • 题目
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);

  • 解法
select date_format(submit_time,'%Y%m') month,
  -- 每用户每天需要唯一
  round(count(distinct uid,date_format(submit_time,'%Y%m%d')) /count(distinct uid),2), 
  count(distinct uid) mau
from exam_record
where year(submit_time)='2021'
group by month


select date_format(day,'%Y%m') month, round(count(day)/count(distinct uid),2),count(distinct uid)
from(
  -- 先过滤好每天的每用户
  select distinct date_format(start_time,'%Y%m%d') day, uid
  from exam_record
  where year(submit_time)='2021'
)t
group by month

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

  • 题目
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);

  • 解法
-- coaleasce 顺序判断返回第一个不为null的值
select coalesce(month,'2021汇总'),month_q_cnt,avg_day_q_cnt from (
select  DATE_FORMAT(submit_time,"%Y%m")  month, 
  count(question_id) month_q_cnt,
  -- 必须多套一层,下面这个无法返回别名
  -- COALESCE (DATE_FORMAT(submit_time, "%Y%m"),"2021汇总") AS submit_month,
  round(count(question_id)/max(right(last_day(submit_time),2)),3) avg_day_q_cnt
from practice_record
where year(submit_time)='2021'
group by month
with rollup 
) t
-- 当月的最后一天日期 dayofmonth(last_day(now())) 
-- 或者 day(last_day(now())) 同理还有year month time函数
-- MySQL提供了 group by with rollup 函数进行group by 字段的汇总,但是与order by 互斥,不能同时用 

select last_day(now()),dayofmonth(now()),dayofmonth(last_day(now()));
+-----------------+-------------------+-----------------------------+
| last_day(now()) | dayofmonth(now()) | dayofmonth(last_day(now())) |
+-----------------+-------------------+-----------------------------+
| 2022-03-31      |                19 |                          31 |
+-----------------+-----

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

  • 题目
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,  
-- 不能用上score,需要submit字段?
-- count(if(score,null,1)) incomplete_cnt,
-- count(if(score,1,null)) complete_cnt,
count(if(submit_time,null,1)) incomplete_cnt,
count(if(submit_time,1,null)) complete_cnt,
-- group_concat([distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'])
group_concat(distinct concat_ws(':', date(start_time), tag) SEPARATOR ';') as detail
from exam_record er 
join examination_info ei on er.exam_id =ei.exam_id 
where year(start_time)='2021'
group by  uid 
having complete_cnt >= 1 and incomplete_cnt < 5 and incomplete_cnt > 1
order by incomplete_cnt DESC
select
uid,  
-- 不能用上score,需要submit字段?
-- count(if(score,null,1)) incomplete_cnt,
-- count(if(score,1,null)) complete_cnt,
count(if(submit_time,null,1)) incomplete_cnt,
count(if(submit_time,1,null)) complete_cnt,
-- group_concat([distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'])
group_concat(distinct concat( date(start_time), ':',tag) SEPARATOR ';') as detail
from exam_record er 
join examination_info ei on er.exam_id =ei.exam_id 
where year(start_time)='2021'
group by  uid 
having complete_cnt >= 1 and incomplete_cnt < 5 and incomplete_cnt > 1
order by incomplete_cnt DESC

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

  • 题目
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 
(select tag from examination_info where exam_id=er.exam_id limit 1 ) tag,count(exam_id) cnt
from exam_record er
where uid in(
  select uid from (
  select uid,date_format(submit_time,'%Y%m') month, count(exam_id) cnt
  from exam_record er
  where submit_time is not null
  group by uid,month having cnt >=3
  ) tmp
)
group by exam_ida
order by cnt desc

-- 去掉标量子查询
select 
tag,count(er.exam_id) cnt
from exam_record er
join examination_info ei on ei.exam_id=er.exam_id
where uid in(
  select uid from (
  select uid,date_format(submit_time,'%Y%m') month, count(exam_id) cnt
  from exam_record er
  where submit_time is not null
  group by uid,month having cnt >=3
  ) tmp
)
group by tag
order by cnt desc

-- 将子查询的次数判断放入having,减少一层嵌套
select 
tag,count(er.exam_id) cnt
from exam_record er
join examination_info ei on ei.exam_id=er.exam_id
where uid in(
  select uid
  from exam_record er
  where submit_time is not null
  group by uid having count(exam_id)/count(distinct date_format(submit_time,'%Y%m')) >=3
)
group by tag
order by cnt desc

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

  • 题目
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 er.exam_id,count(distinct er.uid) uv,round(avg(er.score),1) avg_score
from exam_record er
join user_info u on er.uid=u.uid
join examination_info ei on ei.exam_id= er.exam_id
where u.level >5
AND tag='SQL'
and date(ei.release_time)=date(er.submit_time)
group by exam_id
order by uv desc,avg_score asc


SQL24 分别满足两个活动的人

  • 题目
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);

with tmp as(
select er.uid, er.exam_id,score, timestampdiff(minute, start_time, submit_time)  timed ,ei.duration duration1
from exam_record er 
join examination_info ei on er.exam_id =ei.exam_id
where year(er.submit_time)='2021'
)
select uid,'activity1'
from tmp 
group by uid having min(score) >=85
union all
select distinct uid,'activity2'
from tmp 
join examination_info ei2 on tmp.exam_id=ei2.exam_id
where timed =80
order by uid

-- 输出2021年里  所有每次试卷得分都能到85分的人
select er.uid, 'activity1' activity
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where year(submit_time) ='2021'
group by uid,activity having min(score) >=85

union
-- 输出2021年里 至少有一次用了一半时间就完成高难度试卷且分数大于80的人的id和活动号

select distinct uid,activity from (
  select er.uid, 'activity2' activity,ei.duration*60/2 - TIMESTAMPDIFF(second,start_time,submit_time)  comp_time
  from exam_record er
  join examination_info ei on er.exam_id=ei.exam_id
  and score >80
  and difficulty = 'hard'
  and year(submit_time) ='2021'
) t
where comp_time >=0
order by uid asc

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

  • 题目
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);

  • 解法

-- 高难度SQL试卷得分平均值大于80并且是7级的红名大佬
-- 统计他们的2021年试卷总完成次数和题目总练习次数
-- 只保留2021年有试卷完成记录的用户

-- 1.查找用户
with tmp_u as
(
  select u.uid uid,avg(er.score) score
  from user_info u
  join exam_record er on u.uid=er.uid
  join examination_info ei on er.exam_id=ei.exam_id
  where u.level =7 and ei.tag='SQL' and ei.difficulty ='hard'
  group by uid
  having score >80
),
-- 2.查找考试的用户和统计
tmp_exam as
(
  select uid, count(submit_time) exam_cnt
    from exam_record 
  where year(submit_time)='2021'
  group by uid
),
tmp_prac as
-- 3.查找练习的用户和统计
(
  select uid, count(submit_time) question_cnt
    from practice_record 
  where year(submit_time)='2021'
  group by uid
)
select tmp_exam.uid,tmp_exam.exam_cnt,if(tmp_prac.question_cnt,tmp_prac.question_cnt,0) question_cnt
-- 4.考试左外连练习
from tmp_exam left join tmp_prac on tmp_prac.uid=tmp_exam.uid
-- 5.过滤掉不符合的用户uid
where tmp_exam.uid in (select uid from tmp_u)
order by exam_cnt asc ,question_cnt desc

select exam.uid,exam.exam_cnt,if(question_cnt, question_cnt,0) question_cnt
from
  (
  -- 统计考试的所有用户
  select uid, 
        count(score) as exam_cnt
        from exam_record
        where year(submit_time) = 2021
        group by uid) exam
left join (
     -- 练习的所有用户
     select uid, 
        count(score) as question_cnt
        from practice_record
        where year(submit_time) = 2021
        group by uid) prac on exam.uid=prac.uid
where exam.uid in(
  select u.uid
  from user_info u
  join exam_record er on er.uid=u.uid
  join examination_info ei on ei.exam_id=er.exam_id
  where difficulty='hard'
  and level=7
  and year(er.submit_time)='2021'
  and tag='SQL'
  group by uid having avg(score) > 80
)
order by exam_cnt asc,question_cnt desc


select er.uid,
-- count(distinct exam_id,er.submit_time) as exam_cnt,
-- count(distinct exam_id) as exam_cnt,
exam_id, er.submit_time,question_id,pr.submit_time
-- count(distinct question_id, pr.submit_time) as question_cnt
from exam_record er left join practice_record pr
on er.uid = pr.uid and year(pr.submit_time) = 2021
where er.uid in
(select er.uid
from user_info ui right join exam_record er
on ui.uid = er.uid
left join examination_info ei 
on er.exam_id = ei.exam_id
where tag = "SQL" and difficulty = "hard" and level = 7
group by er.uid
having avg(score) > 80)
and year(start_time) = 2021
and er.submit_time is not null
group by er.uid
order by exam_cnt, question_cnt desc
-- left join 行数增加,需要去重
uid |exam_id|submit_time          |question_id|submit_time          |
----+-------+---------------------+-----------+---------------------+
1001|   9001|2021-09-01 09:31:00.0|       8002|2021-08-02 19:38:01.0|
1001|   9001|2021-09-01 09:31:00.0|       8001|2021-08-02 11:41:01.0|
1003|   9001|2021-09-01 19:40:01.0|           |                     |
1003|   9002|2021-09-01 12:31:51.0|           |                     |

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

  • 题目
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 uid,
count(distinct date_format(submit_time,'%Y%m')) act_month_total,
count(distinct if(date_format(submit_time, '%Y')='2021',date_format(submit_time, '%Y%m%d'),null)) act_days_2021,
count(distinct if(date_format(submit_time, '%Y')='2021' and act='exam',date_format(submit_time, '%Y%m%d'),null)) act_days_2021_exam,
count(distinct if(date_format(submit_time, '%Y')='2021' and act='prac',date_format(submit_time, '%Y%m%d'),null)) act_days_2021_question
from (
select u.uid,submit_time, 'exam' act
from user_info u
left join exam_record er on er.uid=u.uid
where u.level in (6,7)

union all
select u.uid,submit_time, 'prac' act
from user_info u
left join practice_record er on er.uid=u.uid
where u.level in (6,7)
) tmp
group by uid
order by act_month_total desc ,act_days_2021 desc


select 
u.uid,
count(distinct all_month) act_month_total,
count(distinct days_2021) act_days_2021,
count(distinct(
case 
  when year_2021='2021' and tag='exam' then days_2021
  else null
end)) act_days_2021_exam,
count(distinct(
case 
  when year_2021='2021' and tag='prac' then days_2021
  else null
end)) act_days_2021_question
from (
  select uid
  from user_info
  where LEVEL in(6,7)
) u
left join 
(
  select uid, exam_id, 
  date_format(submit_time,'%Y%m') all_month,
  case
    when date_format(submit_time,'%Y')='2021' then  date_format(submit_time,'%Y%m%d')
    else null
  end days_2021,
  case
    when date_format(submit_time,'%Y')='2021' then  date_format(submit_time,'%Y')
    else null
  end year_2021,
  'exam' tag
  from exam_record er
  
  union all
  select uid, question_id,
  date_format(submit_time,'%Y%m') all_month,
  case
    when date_format(submit_time,'%Y')='2021' then  date_format(submit_time,'%Y%m%d')
    else null
  end days_2021,
  case
    when date_format(submit_time,'%Y')='2021' then  date_format(submit_time,'%Y')
    else null
  end year_2021,
  'prac' tag
  from  practice_record pr 
) epall  on u.uid=epall.uid
group by uid
order by act_month_total desc ,act_days_2021 desc

SQL27 每类试卷得分前3名

  • 题目
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 * from (
  select tid,uid,
  rank() over (partition by tid order by m_score desc,min_score desc,uid desc )rk
    from 
    (
      select 
      tag tid,er.uid,max(score) m_score,min(score) min_score
      from exam_record er
      join examination_info ei on er.exam_id=ei.exam_id
      group by tid, uid 
      ) tmp
)  t 
where rk <=3

-- 最内层先出结果,取出所有最大分和最小分
-- 外层开窗分区排序,最大分降序,最大分相同最小分降序,还相同按照uid降序  
-- 即一个人有多次记录,取最好的一次记录
tid|uid |max(score)|min(score)|
---+----+----------+----------+
SQL|1001|        81|        78|
SQL|1002|        81|        81|
SQL|1003|        89|        86|
SQL|1004|        85|        85|
算法 |1005|        85|        85|
算法 |1006|        84|        84|
算法 |1003|        40|        40|

-- 可以减少一层子查询
select tag, uid, ranking
from(
    select tag, e_r.uid,
    row_number() over (partition by tag order by max(score) desc, min(score) desc, e_r.uid desc) as ranking
    from exam_record e_r join examination_info e_i
    on e_r.exam_id = e_i.exam_id
    group by tag, e_r.uid
)ranktable
where ranking <= 3
SELECT b.tag,a.uid,max(a.score),min(a.score),/*这里写max(a.score)和min(a.score)是为了帮助理解窗口函数里的ORDER BY 后面的内容*/
ROW_NUMBER()OVER(PARTITION BY tag ORDER BY max(a.score)DESC,min(a.score)DESC,a.uid DESC) ranking
FROM exam_record a 
LEFT JOIN examination_info b ON a.exam_id=b.exam_id
GROUP BY b.tag,a.uid;
![](https://secure2.wostatic.cn/static/9hszkx8qMxxjfLWT7PzpLL/image.png)

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

  • 题目
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);

  • 解法

    • 第一种方法

      1.通过窗口函数构造一张虚表,存放正序和倒叙用时的数据

select exam_id,timestampdiff(second,start_time,submit_time) used_time,
ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) asc) rk_short_use_time , -- 升序,第二快
ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) desc ) rk_long_use_time -- 降序,第二慢
from exam_record er
where submit_time is not null
+---------+-----------+-------------------+------------------+
| exam_id | used_time | rk_short_use_time | rk_long_use_time |
+---------+-----------+-------------------+------------------+
|    9001 |      1800 |                 2 |                1 |
|    9001 |      1200 |                 1 |                2 |
|    9002 |      3481 |                12 |                1 |
|    9002 |      3420 |                11 |                2 |
|    9002 |      3410 |                10 |                3 |
|    9002 |      1801 |                 9 |                4 |
|    9002 |      1800 |                 5 |                5 |
|    9002 |      1800 |                 6 |                6 |
|    9002 |      1800 |                 7 |                7 |
|    9002 |      1800 |                 8 |                8 |
|    9002 |      1799 |                 4 |                9 |
|    9002 |      1740 |                 3 |               10 |
|    9002 |      1200 |                 2 |               11 |
|    9002 |       540 |                 1 |               12 |
|    9003 |      3480 |                 5 |                1 |
|    9003 |      3010 |                 4 |                2 |
|    9003 |      1801 |                 3 |                3 |
|    9003 |      1201 |                 2 |                4 |
|    9003 |       600 |                 1 |                5 |
  2.两次使用虚表,将相同ID的数据放到一行
with tmp as
(
  select exam_id,timestampdiff(second,start_time,submit_time) used_time,
  ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) asc) rk_short_use_time , -- 升序,第二快
  ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) desc ) rk_long_use_time -- 降序,第二慢
  from exam_record er
  where submit_time is not null
)
select lon.exam_id,long_time,short_time from 
(select exam_id,used_time long_time from tmp where rk_long_use_time=2) lon 
left join (select exam_id,used_time short_time from tmp where rk_short_use_time=2) shor on lon.exam_id=shor.exam_id
+---------+-----------+------------+
| exam_id | long_time | short_time |
+---------+-----------+------------+
|    9001 |      1200 |       1800 |
|    9002 |      3420 |       1200 |
|    9003 |      3010 |       1201 |
+---------+-----------+------------+
  3.和试卷表关联,长时间减去短时间的差值大于duration的一半
with tmp as
(
  select exam_id,timestampdiff(second,start_time,submit_time) used_time,
  ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) asc) rk_short_use_time , -- 升序,第二快
  ROW_NUMBER() over(partition by exam_id order by timestampdiff(second,start_time,submit_time) desc ) rk_long_use_time -- 降序,第二慢
  from exam_record er
  where submit_time is not null
)
select lon.exam_id,long_time,short_time from 
(select exam_id,used_time long_time from tmp where rk_long_use_time=2) lon
left join (select exam_id,used_time short_time from tmp where rk_short_use_time=2) shor on lon.exam_id=shor.exam_id
join examination_info  ei on lon.exam_id=ei.exam_id
where  (long_time - short_time) > duration*60/2
order by exam_id desc

+---------+-----------+------------+
| exam_id | long_time | short_time |
+---------+-----------+------------+
|    9003 |      3010 |       1201 |
|    9002 |      3420 |       1200 |
+---------+-----------+------------+
- 第二种方法

  通过NTH_VALUE取倒叙、升序第二个差值(用时)????

  ![](https://secure2.wostatic.cn/static/3mEDsHcPVvbvdRhAwxrhcQ/image.png)

- 第三种方法
select ei.exam_id,duration,release_time,man_2,kuai_2 from 
(
  select exam_id,max(if(rank2=2,time_diff, null)) man_2,max(if(rank1=2,time_diff, null)) kuai_2
    from (
      select
      exam_id,
      TIMESTAMPDIFF(second,start_time, submit_time) as time_diff
      ,row_number()over(partition by exam_id order by TIMESTAMPDIFF(second,start_time,submit_time)) as rank1  -- 升序最快
      ,row_number()over(partition by exam_id order by TIMESTAMPDIFF(second,start_time,submit_time) desc) as rank2 -- 降序最慢
      from exam_record where submit_time is not null 
    ) t
  group by exam_id 
) tmp
join examination_info ei on ei.exam_id=tmp.exam_id 
where man_2-kuai_2 > duration*60/2
order by exam_id desc
exam_id|duration|release_time         |man_2|kuai_2|
-------+--------+---------------------+-----+------+
   9003|      60|2021-09-01 10:00:00.0| 3010|  1201|
   9002|      60|2021-09-01 08:00:00.0| 3420|  1200|
+---------+-----------+-------+-------+
| exam_id | time_diff | rank1 | rank2 |
+---------+-----------+-------+-------+
|    9001 |      1800 |     2 |     1 |
|    9001 |      1200 |     1 |     2 |
**|    9002 |      3481 |    12 |     1 |
|    9002 |      3420 |    11 |     2 |
|    9002 |      3410 |    10 |     3 |
|    9002 |      1801 |     9 |     4 |
|    9002 |      1800 |     5 |     5 |
|    9002 |      1800 |     6 |     6 |
|    9002 |      1800 |     7 |     7 |
|    9002 |      1800 |     8 |     8 |
|    9002 |      1799 |     4 |     9 |
|    9002 |      1740 |     3 |    10 |
|    9002 |      1200 |     2 |    11 |
|    9002 |       540 |     1 |    12 |**
|    9003 |      3480 |     5 |     1 |
|    9003 |      3010 |     4 |     2 |
|    9003 |      1801 |     3 |     3 |
|    9003 |      1201 |     2 |     4 |
|    9003 |       600 |     1 |     5 |
+---------+-----------+-------+-------+

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

  • 题目
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);
  • 解法
+------------------------------+
| datediff('2022-03-04',now()) |
+------------------------------+
|                          -15 |
+------------------------------+
1 row in set (0.00 sec)

root@hadoop102 18:39:  [test]> select timestampdiff(second,'2022-03-04',now());
+------------------------------------------+
| timestampdiff(second,'2022-03-04',now()) |
+------------------------------------------+
|                                  1363194 |
+------------------------------------------+
1 row in set (0.00 sec)

root@hadoop102 18:39:  [test]> select timestampdiff(second,now(),'2022-03-04');
+------------------------------------------+
| timestampdiff(second,now(),'2022-03-04') |
+------------------------------------------+
|                                 -1363211 |
+------------------------------------------+
with tmp as (
  select
  uid,exam_id,start_time start_time ,
  lead(start_time,1) over (partition by uid order by start_time asc ) next_time
  from exam_record
  where  year(start_time)='2021'
)
select uid, days_windows, round(exam_cnt/diff_days*days_windows,2) avg_exam_cnt
from (
  select uid,
  count(uid) exam_cnt, -- 做过的试卷次数
  datediff(max(next_time),min(start_time)) +1 diff_days,  -- 最大间隔天数 超过1,则表示有两天答题
  max(datediff(next_time,start_time)) +1 days_windows  -- 最大时间窗  要用start_time,submit_time数据不通过
  from tmp
  group by uid
)t 
where diff_days >1
order by days_windows desc ,avg_exam_cnt desc
![](https://secure2.wostatic.cn/static/qK4NrdZAZomjY6r2ZrYRmY/image.png)

![](https://secure2.wostatic.cn/static/qPJYF3QNbqpLPhozLUArpc/image.png)
select uid,days_window,round(cnt/diff_days * days_window,2) avg_exam_cnt from (
  select uid,count(start_time) cnt,
  min(start_time),max(next_start_time),
  datediff(max(next_start_time),min(start_time)) +1 diff_days,
  max(datediff(next_start_time, start_time))+1 days_window 
  from (
    select uid,exam_id,start_time,
    lead(start_time,1) over (partition by uid order by start_time) as next_start_time
    from exam_record
    where year(start_time)='2021'
  ) t
  group by uid
) tmp
where diff_days >=2
order by days_window desc ,avg_exam_cnt desc
with 
a as (  -- 明确用户每次做题相邻时间窗、用户该年参与做题总数
    select uid,
        date(start_time) as st, -- 该用户本次答卷日期
        DATEDIFF(date(lead(start_time) over(partition by uid order by start_time)),date(start_time))+1 as st_window,  -- 该用户相邻答卷天数差时间窗(从题意看,时间差要把起始天算进去,所以+1)
        count(uid) over(partition by uid order by uid) as year_total -- 该用户当年答卷总数
    from exam_record
    where year(start_time)=2021
),
b as ( -- 明确用户最大做题相邻时间窗、用户全年起止做题时间窗
    select uid,
        max(st_window) as max_window, -- 该用户最大相邻时间窗
        year_total,   -- 该用户今年总答卷数
        DATEDIFF(max(st),min(st))+1 as year_window -- 该用户今年起止答卷天数差
    from a
    group by uid
)
select 
    uid,
    max_window as days_window,
    round(year_total/year_window*max_window,2) as avg_exam_cnt -- 题意解释里要求的计算方法
    from b
where max_window>1 -- 题意要求参与至少2天(最大相邻窗口1天的,就只参与了1天,不符合要求)
order by days_window desc,avg_exam_cnt desc

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

  • 题目
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-06-06 10:01:01', '2021-06-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),
(1003, 9003, '2021-09-01 19:01:01', '2021-09-01 19:59:01', 86),
(1003, 9002, '2021-09-03 12:01:01', '2021-09-03 12:57:51', 89),
(1003, 9003, '2021-08-07 12:01:01', '2021-08-07 12:11:01', 40),
(1003, 9003, '2021-05-08 15:01:01', null, null),
(1003, 9002, '2021-06-01 13:01:01', '2021-06-01 13:58:01', 81);
  • 解法 近几个月的用dense_rank
select uid,count(if(score,1,null)) exam_complete_cnt from (
  select uid,exam_id,score,
  dense_rank() over (partition by uid order by date_format(start_time, '%Y%m') desc) rk -- 注意排序要到月份
  from exam_record 
) t
where rk <=3
group by uid having exam_complete_cnt =count(uid)
order by exam_complete_cnt desc,uid desc

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

  • 题目
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);
  • 解法
select tag,exam_cnt_20,exam_cnt_21, growth_rate,
exam_cnt_rank_20,
exam_cnt_rank_21,
cast(exam_cnt_rank_21 as signed) - cast(exam_cnt_rank_20 as signed) rank_delta -- 转为有符号整形
from 
  (
  select tag,exam_cnt_20,exam_cnt_21, 
  concat(round(ifnull((exam_cnt_21-exam_cnt_20)/exam_cnt_20*100,0),1),'%') growth_rate, -- 拼接百分比
  rank() over (order by exam_cnt_20 desc ) exam_cnt_rank_20, -- 为什么是倒序? 去年降序,今年降序,升序的话两年的排名相同了
  rank() over (order by exam_cnt_21 desc) exam_cnt_rank_21
  from 
    (select tag,
    sum(if(date_format(submit_time,'%Y%m') between '202001' and '202006' ,1,0))  exam_cnt_20, -- 行转列1
    sum(if(date_format(submit_time,'%Y%m') between '202101' and '202106' ,1,0))  exam_cnt_21  -- 行转列2
    from exam_record er
    join examination_info ei on er.exam_id=ei.exam_id
    group by tag) t
  )t 
where exam_cnt_20 !=0 and exam_cnt_21 !=0
order by growth_rate desc,exam_cnt_rank_21 desc
![](https://secure2.wostatic.cn/static/pjmf3ciCuZtxs4wdEGFm4H/image.png)

![](https://secure2.wostatic.cn/static/hJTtxB6sDWEvUy6SW58Sma/image.png)

![](https://secure2.wostatic.cn/static/jFGAiK1gMN1iRAx1Kp8HHT/image.png)

![](https://secure2.wostatic.cn/static/sU3mRbW7drGgMEAPwbwfXS/image.png)

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

  • 题目
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(if(max_score!=min_score,(score-min_score)/(max_score-min_score)*100,score))) as new_score 
-- 为什么要判断 max_score!=min_score 某个试卷作答记录中只有一个得分,那么无需使用公式
-- 当min(score)=max(score)那就说明只有一个得分
from
  (select er.uid,er.exam_id,er.score,
  min(score) over (partition by er.exam_id ) min_score,
  max(score) over (partition by er.exam_id ) max_score
  from exam_record er
  join examination_info ei on er.exam_id=ei.exam_id
  where ei.difficulty='hard' and score is not null)
t
group by uid,exam_id
order by exam_id,new_score desc

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

  • 题目
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,start_month,month_cnt,
sum(month_cnt) over (partition by exam_id order by start_month ) cum_exam_cnt
from
  (select distinct exam_id, start_month,
    count(start_month) over (partition by exam_id,start_month order by exam_id,start_month) month_cnt
    from (
    select exam_id, date_format(start_time,'%Y%m') start_month
    from exam_record
    ) t
  ) t
select exam_id,start_month, month_cnt,
-- 每试卷累计按月份排序
sum(month_cnt) over (partition by exam_id order by start_month) cum_exam_cnt
from 
(
    select exam_id,date_format(start_time,'%Y%m') start_month,  
    -- 当月的次数直接分组求count
    count(date_format(start_time,'%Y%m')) month_cnt
    from exam_record
    group by exam_id,start_month
) t

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

  • 题目
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);
  • 解法
    坑1:新增用户的定义——首次登录的用户,也就是把用户最早登录的那天定义为首次登录日期。
    坑2:截止当月的单月最大新增用户数:按照月份依次对比每个月的新增用户数的大小取大值用MAX()OVER(order by start_month)
    坑3:截止当月的累积用户数:按照月份依次累加新增用户数用SUM()OVER(ORDER BY  start_month)

![](https://secure2.wostatic.cn/static/dtrGgQBJ9bZtuqVrMzMf4f/image.png)

![](https://secure2.wostatic.cn/static/kKSwp3AKh9s9vL9tTZa3B9/image.png)

![左外连接](https://secure2.wostatic.cn/static/cte3EaMYzskmgq1KoLahGt/image.png)

![取max当月最大新增用户,累计每月新增的用户](https://secure2.wostatic.cn/static/kkwb2duXbSosgn3ZiuQNKx/image.png)
  • 解法
select start_month,mau,month_add_uv,
max(month_add_uv) over(order by start_month) max_month_add_uv, -- 截止当月的单月最大新增用户数
sum(month_add_uv) over(order by start_month) cum_sum_uv -- 截止当月的累积用户数
from (
select mau_t.start_month,mau_t.mau,if(new_t.month_add_uv,new_t.month_add_uv,0) month_add_uv
from(
  select date_format(start_time ,'%Y%m') start_month,count(distinct uid) mau
  from exam_record
  group by  date_format(start_time ,'%Y%m') )mau_t
left join 
(
  select start_month,count(distinct uid) month_add_uv
  from 
    (select min(date_format(start_time ,'%Y%m')) start_month, uid
    from exam_record
    group by  uid) t
  group by start_month)  new_t on mau_t.start_month=new_t.start_month 
) t
order by start_month

SQL36 统计有未完成状态的试卷的未完成数和未完成率

  • 题目
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-09-02 12:01:01', null, null);

select exam_id,count(if(submit_time,null,1)) incomplete_cnt ,round(sum(if(submit_time,0,1))/count(*),3) incomplete_rate
from exam_record
where exam_id in(select exam_id from exam_record where submit_time is null)
group by exam_id

select exam_id,count(if(submit_time,null,1)) incomplete_cnt ,round(sum(if(submit_time,0,1))/count(*),3) incomplete_rate
from exam_record
group by exam_id
having incomplete_cnt >0  -- 存在为完成

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

  • 题目
 
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);

SELECT er.uid,
round(avg(if(score,score,0)),0) avg_score,
round(avg(TIMESTAMPDIFF(MINUTE,start_time, if(submit_time,submit_time,date_add(start_time,interval duration minute)))),1) submit_time
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
join user_info u on u.uid=er.uid
where level=0 and ei.difficulty='hard'
group by uid

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

  • 题目
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);

select u.uid,nick_name,achievement
from user_info u 
where u.achievement between 1200 and 2500
and u.nick_name like '牛客%号'
and uid in (
  select uid from (
  select uid,max(date_format(submit_time,'%Y%m')) last_month from 
  practice_record pr
  group by uid
  union 
  select uid,max(date_format(start_time,'%Y%m')) last_month from 
  exam_record pr
  group by uid
  ) t where last_month='202109'
)


select u.uid,nick_name,achievement
from user_info u 
where u.achievement between 1200 and 2500
and u.nick_name like '牛客%号'
and uid in (
  select uid from
  practice_record pr
  where date_format(submit_time,'%Y%m')='202109'
  union 
  select uid from
  exam_record pr
  where date_format(start_time,'%Y%m')='202109'
)

select uid,nick_name,achievement
from user_info
where nick_name like '牛客%号' and achievement >= 1200 and achievement <= 2500
and uid in (
            select uid
            from (
                select uid,date_format(start_time,'%Y%m') as month
                from exam_record
                union 
                select uid,date_format(submit_time,'%Y%m') as month
                from practice_record
                ) t
            group by uid
            having max(month) = '202109'
            )

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

  • 题目
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);


select er.uid,er.exam_id,
round(avg(score),0) avg_score
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
where tag regexp('^c|^C')
and er.uid in (
select uid
from user_info u
where u.nick_name regexp('^牛客[0-9]+号$|^[0-9]+$')
)
and er.score is not null
group by uid,exam_id
order by uid asc,avg_score asc

select er.uid,er.exam_id,
round(avg(score),0) avg_score
from exam_record er
join examination_info ei on er.exam_id=ei.exam_id
join user_info u on er.uid=u.uid
where tag regexp('^c|^C')
and u.nick_name regexp('^牛客[0-9]+号$|^[0-9]+$')
and er.score is not null
group by uid,exam_id
order by uid asc,avg_score asc

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

  • 题目
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);
  • 解法
-- 这题需要返回两种情况的结果集
-- 可以在where里面写case表达式
-- 更多的结果集都可以在where里面写case表达式
with tmp as(
select u.uid, 
count(case 
  when start_time is not null and submit_time is not null then 1
  else null
end) complete_cnt,
count(case 
  when start_time is not null and submit_time is null then 1
  else null
end) incomplete_cnt
from user_info u
left join exam_record er on er.uid=u.uid 
group by u.uid
)
select uid, incomplete_cnt, 
round(if(incomplete_cnt/(incomplete_cnt+complete_cnt),incomplete_cnt/(incomplete_cnt+complete_cnt),0),3) incomplete_rate
from tmp
where 
CASE 
  when (
    select max(incomplete_cnt) from (
      select  
      count(case 
        when start_time is not null and submit_time is null then 1
        else null
      end) incomplete_cnt
      from user_info u
      left join exam_record er on er.uid=u.uid 
      where level=0
      group by u.uid) t
  ) > 2 then uid in (select uid from user_info where level=0 )
  else uid in (select uid from exam_record)
end
order by incomplete_rate asc

-- 这是大佬写的
with cte as(
select count(start_time)-count(submit_time) as non_0_num
from exam_record
where uid in (select distinct uid from user_info where level=0) )
#计算出0级用户未完成的试卷量
select if((select* from cte)>2,uid in (select distinct uid from user_info where level=0),uid) as uid,
#if(expr,v1,v2)函数,v1中加入uid范围条件,注意不要直接引用cte,然后就是基操了
count(start_time)-count(submit_time) as non_num,
round((count(start_time)-count(submit_time))/count(start_time),3) as non_rate
from exam_record
group by uid
order by non_rate;

SQL41 各用户等级的不同得分表现占比

  • 题目
 
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', 75),
(1001, 9002, '2021-09-01 12:01:01', '2021-09-01 12:11:01', 60),
(1001, 9003, '2021-09-02 12:01:01', '2021-09-02 12:41:01', 90),
(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, 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', '2020-02-02 12:41:01', 76);

  • 解法
  select u.uid,u.level,er.exam_id,score,
  case
    when score >= 90 then '优'
    when score >=75 and score <90 then '良'
    when score >=60 and score <75 then '中'
    else '差'
  end score_grade
  from exam_record er
  join user_info u on er.uid=u.uid
  where score is not null
![](https://secure2.wostatic.cn/static/xsoyotsnQQbQMQjygvKXBw/image.png)
  select u.uid,u.level,er.exam_id,score,
  case
    when score >= 90 then '优'
    when score >=75 and score <90 then '良'
    when score >=60 and score <75 then '中'
    else '差'
  end score_grade,
  count(*) over(partition by level) user_part_cnt
  from exam_record er
  join user_info u on er.uid=u.uid
  where score is not null
![](https://secure2.wostatic.cn/static/fb2867V8szLoNj67x6jxDB/image.png)
select 
level,score_grade,round(count(score_grade)/user_part_cnt,3) ratio
from (
  select u.uid,u.level,er.exam_id,score,
  case
    when score >= 90 then '优'
    when score >=75 and score <90 then '良'
    when score >=60 and score <75 then '中'
    else '差'
  end score_grade,
  count(*) over(partition by level) user_part_cnt
  from exam_record er
  join user_info u on er.uid=u.uid
  where score is not null
) t
group by level,score_grade
order by level desc,ratio desc

with t1 as
    (select level,
         case when score<60 then '差'
              when score<75 then '中'
              when score<90 then '良'
         else '优' end as grade
    from exam_record
    join user_info
    on exam_record.uid=user_info.uid
    where score is not null)
select t1.level,t1.grade,round(count(grade)/ct,3) cnt
from t1
join 
    (select level,count(level) ct
    from t1
    group by level) t2
on t1.level=t2.level
group by t1.level,t1.grade
order by t1.level desc,cnt desc;

SQL42 注册时间最早的三个人

select 
  uid, nick_name,register_time
from user_info
order by register_time asc limit 3


select uid, nick_name,register_time from 
(
  select 
    uid, nick_name,register_time,
    row_number() over( order by register_time) rk
  from user_info
  ) t
  where rk <=3

SQL45 对过长的昵称截取处理

select uid,
if(char_length(nick_name)> 13,concat(substr(nick_name,1,10),'...'), nick_name) nick_name
from user_info 
where char_length(nick_name) > 10


你可能感兴趣的:(离线数仓,sql)