01 增删改操作
插入记录
SQL1 插入记录(一)
现在有两个用户的作答记录详情如下:
- 用户1001在2021年9月1日晚上10点11分12秒开始作答试卷9001,并在50分钟后提交,得了90分;
- 用户1002在2021年9月4日上午7点1分2秒开始作答试卷9002,并在10分钟后退出了平台。
请用一条语句将这两条记录插入表中。
INSERT INTO exam_record VALUES
(null, 1001, 9001, '2021-09-01 22:11:12', '2021-09-01 23:01:12', 90),
(null, 1002, 9002, '2021-09-04 07:01:02', null, null);
SQL2 插入记录(二)
将2021年之前的已完成了的试题作答纪录导入到exam_record_before_2021表来备份2021年之前的试题作答记录。
INSERT INTO exam_record_before_2021
SELECT NULL, uid, exam_id, start_time, submit_time, score
FROM exam_record
WHERE submit_time < '2021-01-01 00:00:00';
SQL3 插入记录(三)
将 2021-01-01 00:00:00 作为发布时间插入到试题信息表examination_info,不管该ID试卷是否存在,都要插入成功。
REPLACE INTO examination_info
(id, exam_id, tag, difficulty, duration, release_time)
VALUES(null, 9003, 'SQL', 'hard', 90, '2021-01-01 00:00:00')
更新记录
SQL4 更新记录(一)
把examination_info表中tag为PYTHON的tag字段全部修改为Python。
UPDATE examination_info
SET tag ='Python' WHERE tag='PYTHON'
SQL5 更新记录(二)
把exam_record表中2021年9月1日之前开始作答的未完成记录全部改为被动完成,即:将完成时间改为'2099-01-01 00:00:00',分数改为 0。
UPDATE exam_record
SET submit_time='2099-01-01 00:00:00', score=0
WHERE start_time<'2021-09-01' AND submit_time is null
删除记录
SQL6 删除记录(一)
删除exam_record表中作答时间小于5分钟整且分数不及格(及格线为60分)的记录。
DELETE FROM exam_record
WHERE timestampdiff(minute,start_time,submit_time) < 5 AND score < 60
SQL7 删除记录(二)
删除exam_record表中未完成作答或作答时间小于5分钟整的记录中,开始作答时间最早的3条记录。
DELETE FROM exam_record
WHERE timestampdiff(minute, start_time, submit_time) < 5
OR submit_time IS null
ORDER BY start_time
LIMIT 3
SQL8 删除记录(三)
删除exam_record表中所有记录,并重置自增主键。
TRUNCATE TABLE exam_record;
02 表与索引操作
表的创建、修改与删除
SQL9 创建一张新表
创建一张优质用户信息表user_info_vip,表结构和用户信息表一致。
CREATE TABLE IF NOT EXISTS user_info_vip (
id int(11) primary key auto_increment comment '自增ID',
uid int(11) unique not null comment '用户ID',
nick_name varchar(64) comment '昵称',
achievement int(11) default 0 comment '成就值',
level int(11) comment '用户等级',
job varchar(32) comment '职业方向',
register_time datetime default current_timestamp comment '注册时间'
);
SQL10 修改表
在用户信息表,字段level的后面增加一列最多可保存15个汉字的字段school;并将表中job列名改为profession,同时varchar字段长度变为10;achievement的默认值设置为 0。
ALTER TABLE user_info ADD school varchar(15) AFTER LEVEL;
ALTER TABLE user_info CHANGE job profession varchar(10);
ALTER TABLE user_info MODIFY achievement int(11) DEFAULT 0;
SQL11 删除表
删掉(如果存在)(2011到2014年)备份表。
DROP TABLE
IF EXISTS
exam_record_2011,
exam_record_2012,
exam_record_2013,
exam_record_2014;
索引的创建、删除
SQL12 创建索引
为了对表更方便快捷地查询,需要在examination_info表创建以下索引,规则如下:
在duration列创建普通索引idx_duration、在exam_id列创建唯一性索引uniq_idx_exam_id、在tag列创建全文索引full_idx_tag。
# 唯一索引
ALTER TABLE examination_info
ADD UNIQUE INDEX uniq_idx_exam_id(exam_id);
# 全文索引
ALTER TABLE examination_info
ADD FULLTEXT INDEX full_idx_tag(tag);
# 普通索引
ALTER TABLE examination_info
ADD INDEX idx_duration(duration);
SQL13 删除索引
删除examination_info表上的唯一索引uniq_idx_exam_id和全文索引full_idx_tag。
DROP index uniq_idx_exam_id ON examination_info;
DROP index full_idx_tag ON examination_info;
03 聚合分组查询
聚合函数
SQL14 SQL类别高难度试卷得分的截断平均值
从exam_record数据表中计算所有用户完成SQL类别高难度试卷得分的截断平均值(去掉一个最大值和一个最小值后的平均值)。
SELECT tag,difficulty,
round((SUM(score) - MIN(score) - MAX(score)) / (COUNT(score) - 2), 1) as avg_score
FROM examination_info
JOIN exam_record using(exam_id)
WHERE tag='SQL' AND difficulty='hard';
SQL15 统计作答次数
从表中统计出总作答次数total_pv、试卷已完成作答数complete_pv、已完成的试卷数complete_exam_cnt。
SELECT DISTINCT COUNT(*) as total_pv, COUNT(submit_time) as compelete_pv,
COUNT(DISTINCT exam_id AND score IS not NULL) as complete_exam_cnt
FROM exam_record;
SQL16 得分不小于平均分的最低分
从表中找到SQL试卷得分不小于该类试卷平均得分的用户最低得分。
SELECT MIN(score) as min_score_over_avg
FROM examination_info as i
JOIN exam_record as r
ON i.exam_id = r.exam_id
WHERE tag = 'SQL'
AND score >= (
SELECT AVG(score) FROM examination_info as i
JOIN exam_record as r
ON i.exam_id = r.exam_id
WHERE tag = 'SQL'
);
分组查询
SQL17 平均活跃天数和月活人数
计算2021年每个月里试卷作答区用户平均月活跃天数avg_active_days和月度活跃人数mau。
SELECT concat(substr(submit_time, 1, 4), substr(submit_time, 6, 2)) as month,
ROUND(COUNT(DISTINCT uid, day(submit_time)) / COUNT(DISTINCT uid), 2) as avg_active_days,
ROUND(COUNT(DISTINCT(uid)), 0) as mau
FROM exam_record
WHERE submit_time IS NOT null AND year(submit_time) = '2021'
GROUP BY month;
SQL18 月总刷题数和日均刷题数
统计出2021年每个月里用户的月总刷题数month_q_cnt 和日均刷题数avg_day_q_cnt(按月份升序排序)以及该年的总体情况。
SELECT ifnull(a.ymd, '2021汇总'), COUNT(1), ROUND(COUNT(1) / max(da), 3)
FROM (
SELECT DATE_FORMAT(submit_time, '%Y%m') ymd,
DAYOFMONTH(last_day(submit_time)) da
FROM practice_record
WHERE year(submit_time) = '2021'
) a
GROUP BY a.ymd WITH ROLLUP
SQL19 未完成试卷数大于1的有效用户
04 多表查询
嵌套子查询
SQL20 月均完成试卷数不小于3的用户爱作答的类别
SQL21 试卷发布当天作答人数和平均分
SQL22 作答试卷得分大于过80的人的用户等级分布
合并查询
SQL23 每个题目和每份试卷被作答的人数和次数
SQL24 分别满足两个活动的人
连接查询
SQL25 满足条件的用户的试卷完成数和题目练习数
SQL26 每个6/7级用户活跃情况
05 窗口函数
专用窗口函数
SQL27 每类试卷得分前3名
SQL28 第二快/慢用时之差大于试卷时长一半的试卷
SQL29 连续两次作答试卷的最大时间窗
SQL30 近三个月未完成试卷数为0的用户完成情况
SQL31 未完成率较高的50%用户近三个月答卷情况
SQL32 试卷完成数同比2020年的增长率及排名变化
聚合窗口函数
SQL33 对试卷得分做min-max归一化
SQL34 每份试卷每月作答数和截止当月的作答总数。
SQL35 每月及截止当月的答题情况
06 其他常用操作
空值处理
SQL36 统计有未完成状态的试卷的未完成数和未完成率
SQL37 0级用户高难度试卷的平均用时和平均得分
高级条件语句
SQL38 筛选限定昵称成就值活跃日期的用户
SQL39 筛选昵称规则和试卷规则的作答记录
SQL40 根据指定记录是否存在输出不同情况
SQL41 各用户等级的不同得分表现占比
限量查询
SQL42 注册时间最早的三个人
SQL43 注册当天就完成了试卷的名单第三页
文本转换函数
SQL44 修复串列了的记录
SQL45 对过长的昵称截取处理
SQL46 大小写混乱时的筛选统计