SQL 进阶挑战(11 - 15)

146 阅读11分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 14 天,点击查看活动详情

文章首发地址:村雨遥

SQL11 删除表

描述

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

问题

现在随着数据越来越多,存储告急,请你把很久前的(2011到2014年)备份表都删掉(如果存在的话)。

示例

输入:
drop table if EXISTS exam_record;
CREATE TABLE IF NOT EXISTS exam_record (
id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
uid int NOT NULL COMMENT '用户ID',
exam_id int NOT NULL COMMENT '试卷ID',
start_time datetime NOT NULL COMMENT '开始时间',
submit_time datetime COMMENT '提交时间',
score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE TABLE IF NOT EXISTS exam_record_2010 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2012 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2013 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2014 (LIKE exam_record); 
CREATE TABLE IF NOT EXISTS exam_record_2015 (LIKE exam_record); 
输出:
exam_record_2010
exam_record_2015

解答

根据题意可知,2011 - 2014 的备份表的表名分别是:

  • exam_record_2011
  • exam_record_2012
  • exam_record_2013
  • exam_record_2014

要删除一个表,需要用到 DROP TABLE 语句,此外,题意说了如果存在备份表才删除,所以我们需要加入关键字 IF EXISTS,其语法如下,接着套用到本题就可以得到答案。

DROP TABLE [IF EXISTS] [数据表];
DROP TABLE IF EXISTS
exam_record_2011, exam_record_2012, exam_record_2013, exam_record_2014;

SQL12 创建索引

描述

现有一张试卷信息表examination_info,其中包含各种类型试卷的信息。

问题

为了对表更方便快捷地查询,需要在examination_info表创建以下索引,规则如下:

在duration列创建普通索引idx_duration、在exam_id列创建唯一性索引uniq_idx_exam_id、在tag列创建全文索引full_idx_tag。

根据题意,将返回如下结果:

examination_info0PRIMARY1idA0BTREE
examination_info0uniq_idx_exam_id1exam_idA0YESBTREE
examination_info1idx_duration1durationA0BTREE
examination_info1full_idx_tag

示例

输入:
drop table if exists examination_info;
CREATE TABLE IF NOT EXISTS examination_info (
id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
exam_id int UNIQUE NOT NULL COMMENT '试卷ID',
tag varchar(32) COMMENT '类别标签',
difficulty varchar(8) COMMENT '难度',
duration int NOT NULL COMMENT '时长',
release_time datetime COMMENT '发布时间'
)CHARACTER SET utf8 COLLATE utf8_bin;
输出:
examination_info|0|PRIMARY|1|id|A|0|None|None||BTREE|||YES|None
examination_info|0|exam_id|1|exam_id|A|0|None|None||BTREE|||YES|None
examination_info|0|uniq_idx_exam_id|1|exam_id|A|0|None|None||BTREE|||YES|None
examination_info|1|idx_duration|1|duration|A|0|None|None||BTREE|||YES|None
examination_info|1|full_idx_tag|1|tag|None|0|None|None|YES|FULLTEXT|||YES|None

解答

索引有三种,一种是普通索引,其创建方式如下:

CREATE INDEX [索引名] ON [数据表名]([列名]);

第二种是唯一索引,其创建方式如下:

CREATE UNIQUE INDEX [索引名] ON [数据表名]([列名]);

第三种是创建全文索引,其创建方式如下:

CREATE FULLTEXT INDEX [索引名] ON [数据表名]([列名]);

根据题意,得到最终的解答结果如下:

CREATE INDEX idx_duration ON examination_info(duration);
CREATE UNIQUE INDEX uniq_idx_exam_id ON examination_info(exam_id);
CREATE FULLTEXT INDEX full_idx_tag ON examination_info(tag);

SQL13 删除索引

描述

根据上题,完成以下问题。

问题

请删除examination_info表上的唯一索引uniq_idx_exam_id和全文索引full_idx_tag。

示例

输入:
drop table if exists examination_info;
CREATE TABLE IF NOT EXISTS examination_info (
id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
exam_id int COMMENT '试卷ID',
tag varchar(32) COMMENT '类别标签',
difficulty varchar(8) COMMENT '难度',
duration int NOT NULL COMMENT '时长(分钟数)',
release_time datetime COMMENT '发布时间'
)CHARACTER SET utf8 COLLATE utf8_bin;
CREATE INDEX idx_duration ON examination_info(duration);
CREATE UNIQUE INDEX uniq_idx_exam_id ON examination_info(exam_id);
ALTER TABLE examination_info ADD FULLTEXT full_idx_tag(tag);
复制
输出:
examination_info|0|PRIMARY|1|id|A|0|None|None||BTREE|||YES|None
examination_info|1|idx_duration|1|duration|A|0|None|None||BTREE|||YES|None

解答

主要有两种方式,第一种是通过 DROP 的方式,其语法如下:

DROP INDEX [索引名] ON [数据表名];
DROP INDEX uniq_idx_exam_id ON examination_info;
DROP INDEX full_idx_tag ON examination_info;

第二种是通过 ALTER 的方式,其语法如下:

ALTER TABLE [数据表名] DROP INDEX [索引名];
ALTER TABLE examination_info DROP INDEX uniq_idx_exam_id;
ALTER TABLE examination_info DROP INDEX full_idx_tag;

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

描述

牛客的运营同学想要查看大家在SQL类别中高难度试卷的得分情况。

示例数据:examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间)

idexam_idtagdifficultydurationrelease_time
19001SQLhard602020-01-01 10:00:00
29002算法medium802020-08-02 10:00:00

示例数据:exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)

iduidexam_idstart_timesubmit_timescore
1100190012020-01-02 09:01:012020-01-02 09:21:0180
2100190012021-05-02 10:01:012021-05-02 10:30:0181
3100190012021-06-02 19:01:012021-06-02 19:31:0184
4100190022021-09-05 19:01:012021-09-05 19:40:0189
5100190012021-09-02 12:01:01(NULL)(NULL)
6100190022021-09-01 12:01:01(NULL)(NULL)
7100290022021-02-02 19:01:012021-02-02 19:30:0187
8100290012021-05-05 18:01:012021-05-05 18:59:0290
9100390012021-09-07 12:01:012021-09-07 10:31:0150
10100490012021-09-06 10:01:01(NULL)(NULL)

问题

请你帮她从exam_record数据表中计算所有用户完成SQL类别高难度试卷得分的截断平均值(去掉一个最大值和一个最小值后的平均值)。

根据输入你的查询结果如下:

tagdifficultyclip_avg_score
SQLhard81.7

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

输入描述:

输入数据中至少有3个有效分数

示例

输入:
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);
输出:
SQL|hard|81.7

解答

要求除开最大最小值后的平均值,这里需要用到聚合函数 SUM()MAX()MIN() 等,其次,为了统计记录数,需要用到 COUNT() 函数。

要保留平均分的 1 位小数,所以可以用 ROUND() 函数。

其次,要筛选出对应难度为 hard,标签为 SQL 的记录,需要用到 WHERE 筛选,并用 AND 将两个条件串联。

最后,依照题意将上边的细节问题一组合即可。

SELECT tag, difficulty,
    ROUND((SUM(score) - MAX(score) - MIN(score)) / (COUNT(score) - 2), 1) 
AS clip_avg_score
FROM exam_record
JOIN examination_info USING(exam_id)
WHERE 
tag = "SQL" AND difficulty="hard"

SQL15 统计作答次数

描述

有一个试卷作答记录表exam_record。

iduidexam_idstart_timesubmit_timescore
1100190012020-01-02 09:01:012020-01-02 09:21:0180
2100190012021-05-02 10:01:012021-05-02 10:30:0181
3100190012021-06-02 19:01:012021-06-02 19:31:0184
4100190022021-09-05 19:01:012021-09-05 19:40:0189
5100190012021-09-02 12:01:01(NULL)(NULL)
6100190022021-09-01 12:01:01(NULL)(NULL)
7100290022021-02-02 19:01:012021-02-02 19:30:0187
8100290012021-05-05 18:01:012021-05-05 18:59:0290
9100390012021-02-06 12:01:01(NULL)(NULL)
10100390012021-09-07 10:01:012021-09-07 10:31:0188
11100490012021-09-06 12:01:01(NULL)(NULL)

问题

请从中统计出总作答次数total_pv、试卷已完成作答数complete_pv、已完成的试卷数complete_exam_cnt。

示例数据 exam_record表(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)。

示例输出:

total_pvcomplete_pvcomplete_exam_cnt
1172

示例

输入:
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);
输出:
11|7|2

解答

要统计总作答词数、试卷已完成作答数、已完成的试卷数,都只要用一个聚合函数 COUNT(),它会忽略所统计列中值为 NULL 的行。

而针对已完成的试卷数,需要用到 IF 来判断。同时,一套试卷可能会被完成很多次,所以需要去用到 DISTINCT 去重。

SELECT
COUNT(exam_id) AS total_pv,
COUNT(submit_time) AS complete_pv,
COUNT(DISTINCT IF(submit_time IS NOT NULL, exam_id, NULL)) AS complete_exam_cnt
FROM exam_record;