SQL 45道例题

文章目录

0. 数据表创建

  数据表关系图:
SQL 45道例题

创建表SQL语句

-- ---------- 建表语句-----------------
# 学生表 Student:
create table Student( SId varchar(10), Sname varchar(10), Sage datetime, Ssex varchar(10));


# 教师表 Teacher
create table Teacher(
TId varchar(10),
Tname varchar(10)); 


# 科目表 Course
create table Course(
CId varchar(10),
Cname nvarchar(10),
TId varchar(10)); 


# 成绩表 SC
create table SC(
SId varchar(10),
CId varchar(10),
score decimal(18,1)); 


-- ---------- 插入数据语句-----------------

# 学生表 Student:
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('09' , '张三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2017-12-30' , '女');
insert into Student values('12' , '赵六' , '2017-01-01' , '女');
insert into Student values('13' , '孙七' , '2018-01-01' , '女');


# 科目表 Course
insert into Course values('01' , '语文' , '02'); 
insert into Course values('02' , '数学' , '01'); 
insert into Course values('03' , '英语' , '03'); 


# 教师表 Teacher
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四'); 
insert into Teacher values('03' , '王五'); 


# 成绩表 SC
insert into SC values('01' , '01' , 80); 
insert into SC values('01' , '02' , 90); 
insert into SC values('01' , '03' , 99); 
insert into SC values('02' , '01' , 70); 
insert into SC values('02' , '02' , 60); 
insert into SC values('02' , '03' , 80); 
insert into SC values('03' , '01' , 80); 
insert into SC values('03' , '02' , 80); 
insert into SC values('03' , '03' , 80); 
insert into SC values('04' , '01' , 50); 
insert into SC values('04' , '02' , 30); 
insert into SC values('04' , '03' , 20); 
insert into SC values('05' , '01' , 76); 
insert into SC values('05' , '02' , 87); 
insert into SC values('06' , '01' , 31); 
insert into SC values('06' , '03' , 34); 
insert into SC values('07' , '02' , 89); 
insert into SC values('07' , '03' , 98); 

1. 查询" 01 " 课程比 " 02 "课程成绩高的学生的信息及课程分数

-- 1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数  
-- 思路
-- 关键词,“学生信息”,“课程分数”,“课程编号”
-- 1st, 锁定使用表,学生表,成绩表,这两张表提供所有的信息

-- 2nd, 通过SId主键连接学生和成绩表
SELECT 
* 
FROM student a
INNER JOIN sc b
ON a.SId = b.SId;


-- 3rd, 进行同一学生不同成绩的比较,那么就还需再连接一个成绩表,利用Sid相同,Cid不同进行关联。
SELECT 
* 
FROM student a
INNER JOIN sc b
ON a.SId = b.SId
INNER JOIN sc c
ON a.SId = c.SId AND b.CId='01' AND c.CId='02';


-- 4th, 筛选一下课程,利用where比较分数即可
SELECT 
* 
FROM student a
INNER JOIN sc b
ON a.SId = b.SId
INNER JOIN sc c
ON a.SId = c.SId AND b.CId='01' AND c.CId='02'
WHERE b.score > c.score;

1.1 查询同时存在 ‘01’ 课程和 '02’课程的情况

-- 1.1 查询同时存在" 01 "课程和" 02 "课程的情况
-- 思路
-- 关键词,“课程编号” 和 “同时存在”
-- 1st, 锁定所需表,成绩表SC

-- 2nd, 需要用到inner, 
-- join, 实现1名学生的2门课程在同一行,左边的Cid='01'课程,右边的Cid='02'课程
SELECT
*
FROM (SELECT * FROM sc WHERE CId='01') a
INNER JOIN (SELECT * FROM sc WHERE CId='02') b
ON a.SId = b.SId;

-- 3rd, 简化,不用子查询
SELECT
*
FROM sc a
INNER JOIN sc b
ON a.SId = b.SId
WHERE a.CId = '01' AND b.CId = '02'

1.2 查询存在 ‘01’ 课程但可能不存在 ‘02’ 课程的情况(不存在时显示为 null )

-- 1.2 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null ) 
-- 思路
-- 关键词,“01”课程必须 和 “02”课程不必须
-- 1st, 锁定所需表,成绩表SC

-- 2nd, 需要用到left
-- join, 实现1名学生的2门课程在同一行,左边的Cid='01'课程,右边的Cid='02'课程
SELECT
*
FROM (SELECT * FROM sc WHERE CId='01')a
LEFT JOIN sc b
ON a.SId = b.CId AND b.CId='02';

-- 3rd, 简化,不用子查询
SELECT
*
FROM sc a
LEFT JOIN sc b
ON a.SId = b.SId AND b.CId='02'
WHERE a.CId='01';

1.3 查询不存在’01’课程但存在’02’课程的情况

-- 1.3 查询不存在" 01 "课程但存在" 02 "课程的情况
-- 思路
-- 关键词,“01”课程不存在 和 “02”课程存在,使用where语句
-- 1st, 锁定所需表,成绩表SC

-- 2nd, 筛选出存在‘01’情况
SELECT SId FROM sc WHERE CId='01';

-- 3rd, 使用not in筛选出不存在‘01’课程、但是存在‘02’课程的学生
SELECT
*
FROM sc
WHERE SId NOT IN (SELECT SId FROM sc WHERE CId='01') AND CId='02';

2. 查询平均成绩大于等于60分的同学的学生编号和学生平均成绩

-- 2. 查询平均成绩大于等于60分的同学的学生编号和学生平均成绩

-- 分析关键词,“学生编号”, “学生姓名”, “平均成绩>=60”

-- 1st, 锁定使用表,学生表,成绩表

-- 2nd, 成绩表按照Sid聚合,获取平均成绩,并且筛选出平均成绩>=60的Sid 和平均成绩
SELECT 
sid, AVG(score) AS avg_score
FROM sc 
GROUP BY Sid
HAVING avg_score >= 60;

-- 3rd, 利用inner join 连接学生表,获取学生姓名
SELECT
a.SId, a.Sname, avg_score  -- 这里用 a 或 b 一样
FROM student a
INNER JOIN
(SELECT 
sid, AVG(score) AS avg_score
FROM sc 
GROUP BY Sid
HAVING avg_score >= 60) b
ON a.SId = b.SId;

3. 查询在SC表存在成绩的学生信息

-- 3. 查询在SC表存在成绩的学生信息

-- 关键词,“SC表”,“成绩”,“学生信息”

-- 1st, 锁定使用表,学生表,成绩表

-- 2nd, 以成绩表为主,左连接学生表,连接主键Sid,使用left join
SELECT
b.*
FROM sc a
LEFT JOIN student b
ON a.sid = b.sid;


-- 3rd, 使用group by, 从成绩表中取出唯一Sid,左连接学生表
SELECT
b.*
FROM (SELECT sid FROM sc GROUP BY SId) a    -- 去重
LEFT JOIN student b
ON a.sid = b.sid;

4. 查询所有同学的学生编号,学生姓名,选课总数,所有课程的总成绩(没成绩的显示为null)

-- 4. 查询所有同学的学生编号,学生姓名,选课总数,所有课程的总成绩(没成绩的显示为null)

-- 关键词,“学生信息”,“选课总数”,“所有课程总成绩”

-- 1st, 锁定使用表,学生表,成绩表

-- 2nd, 在SC表中对Sid进行聚合,获取每个学生的选课总数,所有课程总成绩
SELECT
sid, 
COUNT(CId) as ct,
SUM(score) as sum_score
FROM sc
GROUP BY Sid;  -- 大小写无影响

-- 3rd, 学生表为主表,与第二步得到的成绩汇总表进行左连接
SELECT
a.SId, a.Sname, b.ct, b.sum_score
FROM Student a
LEFT JOIN 
(SELECT
sid, 
COUNT(CId) as ct,
SUM(score) as sum_score
FROM sc
GROUP BY Sid) b
ON a.SId = b.SId;

4.1 查询有成绩的学生信息

-- 4.1 查询有成绩的学生信息

-- 1st, 锁定使用表,学生表,成绩表

-- 2nd, 筛选出有成绩的Sid
SELECT SId FROM sc GROUP BY SId;

-- 3rd, 利用有成绩的Sid对student表做筛选
SELECT
*
FROM student
WHERE sid IN(SELECT SId FROM sc GROUP BY SId);

5. 查询‘李’姓老师的数量

-- 5. 查询‘李’姓老师的数量

-- 关键词,“老师”, “李”,“数量”

-- 1st, 锁定表,教师表

-- 2nd, 筛选出‘李’姓老师(提示:使用 like,% 代表占位符)
SELECT 
*
FROM teacher
WHERE Tname LIKE '李%';

-- 统计‘李’姓老师的数量
SELECT 
COUNT(*)
FROM teacher
WHERE Tname LIKE '李%';

6.查询学过‘张三’老师授课的同学的信息

-- 6.查询学过‘张三’老师授课的同学的信息

-- 关键词,“教师姓名”,“同学信息”

-- 1st, 锁定表,教师表,课程表,成绩表,学生表

-- 2nd,关联课程表和教师表,得到课程Cid与教师Tname的关系
SELECT a.*,Tname FROM course a INNER JOIN teacher b ON a.TId=b.TId; 

-- 3rd, 与成绩表关联,得到学生Sid与教师Tname的关系
SELECT a.*,Tname FROM sc a
INNER JOIN (SELECT a.*,Tname FROM course a INNER JOIN teacher b ON a.TId=b.TId GROUP BY Tname) b
ON a.CId = b.cid;


-- 4th,与学生表关联,获取学生信息
SELECT a.*,Tname FROM student a
INNER JOIN (SELECT a.*,Tname FROM sc a
INNER JOIN (SELECT a.*,Tname FROM course a INNER JOIN teacher b ON a.TId=b.TId) b
ON a.CId = b.cid) b    
ON a.SId = b.SId;

-- 5th, 增加筛选条件,Tname=‘张三’
SELECT a.*,Tname FROM student a
INNER JOIN (SELECT a.*,Tname FROM sc a
INNER JOIN (SELECT a.*,Tname FROM course a INNER JOIN teacher b ON a.TId=b.TId) b
ON a.CId = b.cid) b
ON a.SId = b.SId
WHERE Tname='张三';

7. 查询没有学全所有课程的同学的信息

-- 7. 查询没有学全所有课程的同学的信息

-- 关键词,“同学信息”,“所有课程”

-- 1st, 锁定表,学生表,成绩表,课程表

-- 2nd, 根据课程表,获取全部课程总数
SELECT COUNT(CId) FROM course;

-- 3rd, 根据成绩表,获取每个学生的所学课程总数,并筛选出所学课程总数小于全部课程总数的学生SId
SELECT 
sid, COUNT(CId) as ct
FROM sc
GROUP BY SId
HAVING ct < (SELECT COUNT(CId) FROM course);

-- 4th, 关联学生表,获取学生信息
SELECT
a.*, ct 
FROM student a
INNER JOIN 
(SELECT 
sid, COUNT(CId) as ct
FROM sc
GROUP BY SId
HAVING ct < (SELECT COUNT(CId) FROM course)) b
ON a.SId = b.SId;

8. 查询至少一门课与学号为“01”的同学 所学相同的同学 的信息

-- 8. 查询至少一门课与学号为“01”的同学 所学相同的同学 的信息

-- 关键词,“学生信息”, “课程”

-- 1st, 锁定表,成绩表,学生表

-- 2nd, 根据成绩表,获取“01”同学所学课程的编号
SELECT CId FROM sc WHERE SId='01';


-- 3rd, 使用in, 获取课程编号在“01”同学所学课程编号 范围内的记录
SELECT
* 
FROM sc
WHERE CId in (SELECT CId FROM sc WHERE SId='01');


-- 4th, 关联学生表,获取学生信息
SELECT
DISTINCT a.*  -- DISTINCT 去重
FROM student a
INNER JOIN
(SELECT
* 
FROM sc
WHERE CId in (SELECT CId FROM sc WHERE SId='01')) b
ON a.SId = b.SId;

9. 查询和“01”号同学学习的课程 完全相同 的其他同学的信息

-- 9. 查询和“01”号同学学习的课程 完全相同 的其他同学的信息

-- 关键词,“学生信息”,“课程”,“完全相同”
-- “完全相同” 两层含义,1. 没有学习“01”号同学学习课程以外的其他课程;2. 与“01”号同学学习课程数量相等

-- 1st, 锁定表,学生表,成绩表

-- 2nd, 找出学了“01”号同学学习课程以外其他课程的同学
SELECT sid FROM sc WHERE CId not in (SELECT cid FROM sc WHERE SId='01');

-- 3rd, 排除第二步找到的同学以及“01”号同学
SELECT SId FROM sc
WHERE sid NOT IN (SELECT sid FROM sc WHERE CId not in (SELECT cid FROM sc WHERE SId='01')) AND SId != '01'
GROUP BY SId;  # GROUP BY 这里去重


-- 4th, 筛选出与“01”号同学学习课程数量相等的同学
SELECT SId FROM sc
WHERE sid NOT IN (SELECT sid FROM sc WHERE CId not in (SELECT cid FROM sc WHERE SId='01')) AND SId != '01'
GROUP BY SId
HAVING COUNT(CId) = (SELECT COUNT(CId) FROM sc WHERE SId='01');


-- 5th, 关联学生表,获取学生信息
SELECT
b.*
FROM 
(SELECT SId FROM sc
WHERE sid NOT IN (SELECT sid FROM sc WHERE CId not in (SELECT cid FROM sc WHERE SId='01')) AND SId != '01'
GROUP BY SId
HAVING COUNT(CId) = (SELECT COUNT(CId) FROM sc WHERE SId='01')) a
INNER JOIN student b
ON a.SId = b.SId;

10. 查询没学过“张三”老师讲授的任一们课程的学生姓名

-- 10. 查询没学过“张三”老师讲授的任一们课程的学生姓名

-- 关键词,“学生姓名”,“张三老师”

-- 1st, 锁定表,4张表

-- 2nd, 关联课程表和教师表,筛选出张三老师讲授课程的cid
SELECT * FROM course a INNER JOIN teacher b ON a.TId=b.TId WHERE Tname='张三';


-- 3rd, 关联成绩表,获取学过张三老师课程的sid
SELECT sid FROM sc a
LEFT JOIN course b
ON a.CId=b.CId
INNER JOIN teacher c
ON b.TId=c.TId
WHERE Tname='张三';

-- 4th, 关联学生表,使用not in, 筛选出没有学过“张三”老师课程的Sid
SELECT
Sname
FROM student a
WHERE SId NOT IN (SELECT sid FROM sc a
LEFT JOIN course b
ON a.CId=b.CId
INNER JOIN teacher c
ON b.TId=c.TId
WHERE Tname='张三');

11. 查询两门及以上不及格课程的同学的学号,姓名及其平均成绩

-- 11. 查询两门及以上不及格课程的同学的学号,姓名及其平均成绩

-- 关键词,“学号姓名”,“平均成绩”,“课程”

-- 1st, 锁定表,学生表,成绩表

-- 2nd, 求学生的平均成绩
SELECT SId, AVG(score) as avg_score FROM sc GROUP BY SId;


-- 3rd, 找出两门及以上不及格课程的同学
SELECT SId FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2;


-- 4th, 结合第2和3步,求有两门及以上课不及格课程的同学的平均成绩
SELECT a.SId, AVG(score) as avg_score   -- 这里两个表a,b 都有sid, 选择sid时要变为a.SId
FROM sc a
INNER JOIN (
SELECT SId FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2) b
ON a.SId = b.SId
GROUP BY a.SId;  


-- 5th, 关联学生表,获取学生学号
SELECT
a.SId, b.Sname, avg_score
FROM (SELECT a.SId, AVG(score) as avg_score   
FROM sc a
INNER JOIN (
SELECT SId FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2) b
ON a.SId = b.SId
GROUP BY a.SId) a
LEFT JOIN student b
ON a.SId=b.SId;

12. 检索“01”课程分数小于60,按分数降序排列的学生信息

-- 12. 检索“01”课程分数小于60,按分数降序排列的学生信息

-- 关键词,“学生信息”,“课程分数”,“降序”

-- 1st, 锁定表,学生表,成绩表

-- 2nd, 筛选“01”课程分数小于60的Sid
SELECT SId,score FROM sc WHERE CId='01' AND score<60;


-- 3rd, 关联学生表,获取学生信息,并按照分数降序排列
SELECT 
b.*, a.score
FROM (SELECT SId,score FROM sc WHERE CId='01' AND score<60) a
LEFT JOIN student b
ON a.SId = b.SId
ORDER BY a.score DESC; 

13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

-- 13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

-- 关键词, “所有学生”,“所有课程”,“平均成绩”

-- 1st, 锁定使用表,学生表,成绩表

-- 2nd, 获取所有学生的所有课程成绩(学生表左连接成绩表,没有成绩显示null)
SELECT 
a.SId, b.CId, b.score
FROM student a
LEFT JOIN sc b
on a.SId = b.SId;


-- 3rd, 求学生平均成绩
SELECT
sid, AVG(score) as avg_score
FROM sc
GROUP BY sid;


-- 4th, 给每条成绩加上平均成绩,最终按照平均成绩降序排序
SELECT
a.SId, a.CId, a.score, avg_score
FROM (SELECT a.SId, b.CId, b.score FROM student a LEFT JOIN sc b on a.SId = b.SId) a
LEFT JOIN (SELECT sid, AVG(score) as avg_score FROM sc GROUP BY sid) b
ON a.SId = b.SId
ORDER BY b.avg_score DESC;

14. 查询各科成绩最高分,最低分和平均分

-- 14. 查询各科成绩最高分,最低分和平均分

-- 以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
-- 及格为:>=60, 中等:[70,80), 优良[80,90), 优秀>=90
-- 要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列

-- 分析题目:课程号、课程名称、聚合计算(选修人数、最高分、最低分,平均分,及格率,中等率,优良率,优秀率)、排序

-- 1st, 确定使用表,成绩表,课程表

-- 2nd, 聚合计算(使用条件判断语句 case when)
SELECT 
CId,
COUNT(*) AS 选修人数,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
AVG(score) AS 平均分,
SUM(CASE WHEN score>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格率,  
SUM(CASE WHEN score>=70 AND score<80 THEN 1 ELSE 0 END)/COUNT(*) AS 中等率, 
SUM(CASE WHEN score>=80 AND score<90 THEN 1 ELSE 0 END)/COUNT(*) AS 良好率, 
SUM(CASE WHEN score>=90 THEN 1 ELSE 0 END)/COUNT(*) AS 优秀率
FROM sc
GROUP BY CId;


-- 3rd, 排序(按照选修人数降序、课程号升序排列)
SELECT
CId,
COUNT(*) AS 选修人数,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
AVG(score) AS 平均分,
SUM(CASE WHEN score>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格率,  
SUM(CASE WHEN score>=70 AND score<80 THEN 1 ELSE 0 END)/COUNT(*) AS 中等率, 
SUM(CASE WHEN score>=80 AND score<90 THEN 1 ELSE 0 END)/COUNT(*) AS 良好率, 
SUM(CASE WHEN score>=90 THEN 1 ELSE 0 END)/COUNT(*) AS 优秀率
FROM sc
GROUP BY CId
ORDER BY COUNT(*) DESC, CId ASC; 


-- 4th, 关联课程表,获取cname
SELECT
a.*, Cname
FROM (SELECT
CId,
COUNT(*) AS 选修人数,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
AVG(score) AS 平均分,
SUM(CASE WHEN score>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格率,  
SUM(CASE WHEN score>=70 AND score<80 THEN 1 ELSE 0 END)/COUNT(*) AS 中等率, 
SUM(CASE WHEN score>=80 AND score<90 THEN 1 ELSE 0 END)/COUNT(*) AS 良好率, 
SUM(CASE WHEN score>=90 THEN 1 ELSE 0 END)/COUNT(*) AS 优秀率
FROM sc
GROUP BY CId
ORDER BY COUNT(*) DESC, CId ASC) a
LEFT JOIN course b
ON a.CId = b.CId;

15. 按各科成绩进行排序,并显示排名,score重复时也继续排名

知识点:ROW_NUMBER(),RANK(), DENSE_RANK() 区别

  1. ROW_NUMBER(): 依次排序,不会出现相同排名
  2. RANK(): 出现相同排名时,跳跃排名
  3. DENSE_RANK(): 出现相同排名时,连续排名
-- 15. 按各科成绩进行排序,并显示排名,score重复时也继续排名

SELECT
*,
ROW_NUMBER() over (PARTITION by CId ORDER BY score DESC) AS 排名
FROM sc;


-- 15.1 按各科成绩进行排序,并显示排名,score 重复时合并名次
SELECT
*,
RANK() over (PARTITION by CId ORDER BY score DESC) AS 排名
FROM sc;

SELECT
*,
DENSE_RANK() over (PARTITION by CId ORDER BY score DESC) AS 排名
FROM sc;

16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺

-- 16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺

-- 关键词,“总分”,“保留名次空缺”

-- 1st, 计算总成绩
SELECT 
SId, SUM(score) AS sum_score
FROM sc
GROUP BY SId;

-- 2nd, 按总成绩排名,排名跳跃
SELECT
*,
RANK() over (ORDER BY sum_score DESC) AS 排名
FROM (SELECT 
SId, SUM(score) AS sum_score
FROM sc
GROUP BY SId) a;


-- 16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺

-- 关键词,“总分”,“不保留名次空缺”

-- 1st, 计算总成绩

-- 2nd, 按总成绩排名,排名连续
SELECT
*,
DENSE_RANK() over (ORDER BY sum_score DESC) AS 排名
FROM (SELECT 
SId, SUM(score) AS sum_score
FROM sc
GROUP BY SId) a;

17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比

-- 17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比

-- 关键词,“课程编号”, “课程名称”, “分数段”, “人数”

-- 1st, 锁定表,成绩表,课程表

-- 2nd, 使用case when, 按照课程编号统计各分数段人数
SELECT 
CId,
SUM(case when score>=0 and score<60 then 1 else 0 END) as '[60-0]',
SUM(case when score>=60 and score<70 then 1 else 0 END) as '[70-60]',
SUM(case when score>=70 and score<85 then 1 else 0 END) as '[85-70]',
SUM(case when score>=85 and score<=100 then 1 else 0 END) as '[100-85]'
FROM sc
GROUP BY CId;


-- 3rd, 转化成所占百分比
SELECT 
CId,
SUM(case when score>=0 and score<60 then 1 else 0 END)/COUNT(*) as '[60-0]',
SUM(case when score>=60 and score<70 then 1 else 0 END)/COUNT(*) as '[70-60]',
SUM(case when score>=70 and score<85 then 1 else 0 END)/COUNT(*) as '[85-70]',
SUM(case when score>=85 and score<=100 then 1 else 0 END)/COUNT(*) as '[100-85]'
FROM sc
GROUP BY CId;


-- 4th, 使用concat拼接,输出百分比符号
SELECT 
CId,
CONCAT(SUM(case when score>=0 and score<60 then 1 else 0 END)/COUNT(*)*100, '%') as '[60-0]',
CONCAT(SUM(case when score>=60 and score<70 then 1 else 0 END)/COUNT(*)*100, '%') as '[70-60]',
CONCAT(SUM(case when score>=70 and score<85 then 1 else 0 END)/COUNT(*)*100, '%') as '[85-70]',
CONCAT(SUM(case when score>=85 and score<=100 then 1 else 0 END)/COUNT(*)*100, '%') as '[100-85]'
FROM sc
GROUP BY CId;


-- 5th, 关联课程表,输出课程名称
SELECT
a.*, b.Cname
FROM 
(SELECT 
CId,
CONCAT(SUM(case when score>=0 and score<60 then 1 else 0 END)/COUNT(*)*100, '%') as '[60-0]',
CONCAT(SUM(case when score>=60 and score<70 then 1 else 0 END)/COUNT(*)*100, '%') as '[70-60]',
CONCAT(SUM(case when score>=70 and score<85 then 1 else 0 END)/COUNT(*)*100, '%') as '[85-70]',
CONCAT(SUM(case when score>=85 and score<=100 then 1 else 0 END)/COUNT(*)*100, '%') as '[100-85]'
FROM sc
GROUP BY CId) a
LEFT JOIN course b
ON a.CId = b.CId;

18. 查询各科成绩前三名的记录

-- 18. 查询各科成绩前三名的记录

-- 关键词,“各科成绩”,“前三名”

-- 1st, 各科成绩排名
SELECT 
*, 
DENSE_RANK() over (PARTITION by CId ORDER BY score DESC) as score_rank    -- PARTITION 分区
FROM sc;


-- 2nd, 筛选前三名
SELECT
*
FROM (SELECT 
*, 
DENSE_RANK() over (PARTITION by CId ORDER BY score DESC) as score_rank    -- PARTITION 分区
FROM sc) a
WHERE score_rank <=3;

19. 查询每门课程被选修的学生数

-- 19. 查询每门课程被选修的学生数

-- 关键词,“每门课程”, “学生数”

-- 1st, 锁定表,成绩表

-- 2nd, 按照课程编号进行分组排序
SELECT
cid,
COUNT(*) AS 学生数
FROM sc
GROUP BY CId;

20. 查询出只选修两门课程的学生学号和姓名

-- 20. 查询出只选修两门课程的学生学号和姓名

-- 关键词,“两门课程”,“学生学号和姓名”

-- 1st, 锁定表,成绩表,学生表

-- 2nd, 统计每个学生选修课程数,并筛选出只选修2门课程的学生Sid
SELECT
sid,
COUNT(*) as ct
FROM sc
GROUP BY SId
HAVING ct=2;

-- 3rd, 关联学生表,输出学生姓名
SELECT
a.sid, b.Sname
FROM (
SELECT
sid,
COUNT(*) as ct
FROM sc
GROUP BY SId
HAVING ct=2) a
LEFT JOIN student b
ON a.sid = b.SId;

21. 查询男生、女生人数

-- 21. 查询男生、女生人数

-- “不同性别”, “人数”

-- 1st, 锁定表,学生表

-- 2nd, 按照性别进行分组统计

SELECT 
Ssex,
COUNT(*) as ct
FROM student
GROUP BY Ssex;

22. 查询名字中含有‘风’字的学生信息

-- 22. 查询名字中含有‘风’字的学生信息

-- 关键词,“名字中含有‘风’”,“学生信息”

-- 1st, 锁定表,学生表

-- 2nd, 使用like操作符,%为占位符

SELECT
*
FROM student
WHERE Sname LIKE '%风%';

23. 查询同名同性别学生名单,并统计同名同性别人数

-- 23. 查询同名同性别学生名单,并统计同名同性别人数

-- 关键词,“同名同性别”,“人数”

-- 1st, 锁定表,学生表

-- 2nd, 自连接查询,筛选出名字,性别相同

SELECT
a.*
FROM student a
INNER JOIN student b
ON a.Sname = b.Sname AND a.Ssex = b.Ssex AND a.SId != b.SId;

-- 3rd, 统计同名同性别的人数

SELECT
Sname,
Ssex,
COUNT(*) as ct
FROM (SELECT
a.*
FROM student a
INNER JOIN student b
ON a.Sname = b.Sname AND a.Ssex = b.Ssex AND a.SId != b.SId) a
GROUP BY Sname, Ssex;

24. 查询1990年出生的学生名单

-- 24. 查询1990年出生的学生名单

-- 关键词,“出生日期”

-- 1st, 锁定表, 学生表
SELECT * FROM student;


-- 2nd, 使用year(), 筛选出1900年出生的学生
SELECT 
*
FROM student
WHERE YEAR(Sage)='1990';


-- left()
SELECT 
*
FROM student
WHERE left(Sage, 4)='1990';

25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列

-- 25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列

-- 关键词,“平均成绩”,“排序”

-- 1st, 锁定表,成绩表

-- 2nd, 计算每门课程的平均成绩
SELECT
CId,
AVG(score) as avg_score
FROM sc
GROUP BY CId;


-- 3rd, 排序(按照平均成绩降序,课程编号升序)
SELECT
CId,
AVG(score) as avg_score
FROM sc
GROUP BY CId
ORDER BY avg_score DESC, cid ASC;

26. 查询平均成绩大于等于 85 的所有学生的学号,姓名和平均成绩

-- 26. 查询平均成绩大于等于 85 的所有学生的学号,姓名和平均成绩

-- 关键词,“平均成绩”,“学号”,“姓名”

-- 1st, 锁定表,成绩表,学生表

-- 2nd, 分组聚合求出每个学生平均分数,并筛选出平均分大于等于85分的学生
SELECT
sid,
AVG(score) AS avg_score
FROM sc
GROUP BY SId
HAVING avg_score >= 85;


-- 3rd, 关联学生表,获取学生姓名
SELECT
a.sid, b.Sname, avg_score
FROM (
SELECT
sid,
AVG(score) AS avg_score
FROM sc
GROUP BY SId
HAVING avg_score >= 85) a
LEFT JOIN student b
ON a.sid = b.SId;

27. 查询课程名称为“数学”,且分数低于60的学生姓名和分数

-- 27. 查询课程名称为“数学”,且分数低于60的学生姓名和分数

-- 关键词,“课程名称”,“分数”, “学生姓名”

-- 1st, 课程表,成绩表,学生表

-- 2nd, 求出课程名称为数学的课程编号
SELECT cid FROM course WHERE Cname='数学';

-- 3rd, 成绩表关联学生表,查询数学分数低于60分的学生信息

SELECT 
b.SId,
b.Sname,
a.CId,
a.score
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
WHERE CId=(SELECT cid FROM course WHERE Cname='数学') AND score<60;

28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)

-- 28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)

-- 关键词,“所有学生”,“课程”,“分数”

-- 1st, 锁定表,学生表,成绩表

-- 2nd, 学生表左连接成绩表
SELECT
*
FROM student a
LEFT JOIN sc b
ON a.SId = b.SId;

29.查询任何一门课程成绩在70分以上的姓名,课程名称和分数

-- 29.查询任何一门课程成绩在70分以上的姓名,课程名称和分数

-- 关键词,“学生姓名”,“课程名称”,“分数”

-- 1st, 锁定表, 学生表,课程表,成绩表

-- 2nd, 关联成绩表和课程表,并筛选出成绩在70分以上的记录
SELECT
*
FROM sc a
LEFT JOIN course b
ON a.CId = b.CId
WHERE a.score>70;


-- 3rd, 关联学生表,获取学生姓名
SELECT
Sname,Cname,score
FROM sc a
LEFT JOIN course b
ON a.CId = b.CId
LEFT JOIN student c
ON a.SId = c.SId
WHERE  a.score>70;

30. 查询存在不及格的课程

-- 30. 查询存在不及格的课程

-- 关键词,"不及格", "课程"

-- 1st, 锁定表,成绩表,课程表

-- 2nd, 筛选出低于60分的课程的cid
SELECT
DISTINCT CId
FROM sc 
WHERE score<60;


-- 3rd, 使用子查询,获取课程信息
SELECT
*
FROM course
WHERE CId IN (SELECT
DISTINCT CId
FROM sc 
WHERE score<60);

31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名

-- 31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名

-- 关键词,“课程编号”,“成绩”, “学生学号”,“姓名”

-- 1st, 锁定表,成绩表,学生表

-- 2nd, 关联查询
SELECT
a.*, 
b.Sname
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
WHERE a.CId = '01' AND a.score>=80;

32. 求每门课程的学生人数

-- 32. 求每门课程的学生人数

-- 关键词,“每门课程”, “人数”

-- 1st, 锁定表,成绩表

-- 2nd, 分组聚合
SELECT
cid,
COUNT(*) AS ct
FROM sc 
GROUP BY cId;

33. 假设成绩不重复,查询选修“张三” 老师所授课程的学生中,成绩最高的学生信息及其成绩

-- 33. 假设成绩不重复,查询选修“张三” 老师所授课程的学生中,成绩最高的学生信息及其成绩

-- 关键词,“张三老师”,“成绩不重复”,“成绩最高”,“学生信息”,“成绩”

-- 锁定表, 4张表

-- 1st, 关联4张表
SELECT
*
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId;


-- 2nd, 增加筛选条件,‘张三’老师
SELECT
*
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId
WHERE Tname = '张三';


-- 3rd, 按照分数排序,只显示第一条记录(limit)
SELECT
b.*, score, Tname
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId
WHERE Tname = '张三'
ORDER BY score DESC
LIMIT 1;

34. 假设成绩有重复的情况下,查询选修‘张三’老师所授的学生中,成绩最高的学生信息及其成绩

-- 34.  假设成绩有重复的情况下,查询选修‘张三’老师所授的学生中,成绩最高的学生信息及其成绩

-- 关键词,“张三老师”, “成绩重复”,“成绩最高”,“学生信息”,“成绩”

-- 1st,锁定表,教师表,课程表,成绩表,学生表

-- 2nd, 关联4张表,并筛选出选修‘张三’老师所授课程的记录
SELECT
*
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId
WHERE Tname = '张三';


-- 3rd, 使用dense_rank()进行排序
SELECT
b.*, a.score, d.Tname,
DENSE_RANK() over (ORDER BY score DESC) AS score_rank
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId
WHERE Tname = '张三';


-- 4th, 筛选出第1名
SELECT
*
FROM (
SELECT
b.*, a.score, d.Tname,
DENSE_RANK() over (ORDER BY score DESC) AS score_rank
FROM sc a
LEFT JOIN student b
ON a.SId = b.SId
LEFT JOIN course c
ON a.CId = c.CId
LEFT JOIN teacher d
ON c.Tid = d.TId
WHERE Tname = '张三') a
WHERE score_rank = 1;

35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

-- 35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

-- 关键词,“不同课程”、“成绩相同”

-- 1st, 锁定表,成绩表

-- 2nd, 自连接成绩表,连接条件是学生编号相同、课程编号不同、成绩相同
SELECT
*
FROM sc a
INNER JOIN sc b
ON a.SId = b.SId AND a.CId != b.CId AND a.score = b.score;


-- 3rd, 去重
SELECT
DISTINCT a.*
FROM sc a
INNER JOIN sc b
ON a.SId = b.SId AND a.CId != b.CId AND a.score = b.score;

36. 查询每门科目成绩最好的前两名

-- 36. 查询每门科目成绩最好的前两名

-- 关键词,“每门科目”, “成绩最好前两名”

-- 1st, 锁定表,成绩表

-- 2nd, 使用dense_rank()排名
SELECT
*,
DENSE_RANK() over (PARTITION by CId ORDER BY score DESC) AS score_rank
FROM sc;


-- 3rd, 筛选出前两名
SELECT
*
FROM (SELECT
*,
DENSE_RANK() over (PARTITION by CId ORDER BY score DESC) AS score_rank
FROM sc) a
WHERE score_rank<=2;

37. 统计每门课程的学生选修人数(超过5人的课程才统计)

-- 37. 统计每门课程的学生选修人数(超过5人的课程才统计)

-- 关键词,“每门课程”,“选修人数”、“超过5人才统计”

-- 1st, 锁定表,成绩表

-- 2nd, 分组聚合,求每门课程的选修人数
SELECT
cid,
COUNT(*) AS ct
FROM sc
GROUP BY CId; 


-- 3rd, 筛选出选修人数大于5的记录
SELECT
cid,
COUNT(*) AS ct
FROM sc
GROUP BY CId
HAVING ct>5; 

38. 检索至少选修两门课程的学生学号

-- 38. 检索至少选修两门课程的学生学号

-- 关键词,“选修课程”, “学生学号”

-- 1st, 锁定表, 成绩表

-- 2nd, 分组聚合,求出每名学生的选修课程数
SELECT
SId,
COUNT(*) as ct
FROM sc
GROUP BY SId;

-- 3rd, 筛选出选修课程数大于等于2的学生
SELECT
SId,
COUNT(*) as ct
FROM sc
GROUP BY SId
HAVING ct>=2;

39. 查询选修了全部课程的学生信息

-- 39. 查询选修了全部课程的学生信息

-- 关键词,“选修全部课程”,“学生信息”

-- 1st, 锁定表,学生表,成绩表,课程表

-- 2nd, 求出课程表的总课程数
SELECT COUNT(*) FROM course; 


-- 3rd, 求出每名学生的选修课程数
SELECT
SId,
COUNT(*) 
FROM sc
GROUP BY SId;


-- 4th, 筛选出学习全部课程的学生sid
SELECT
SId,
COUNT(*) 
FROM sc
GROUP BY SId
HAVING count(*) = (SELECT COUNT(*) FROM course);


-- 5th, 使用子查询,获取学生信息
SELECT
*
FROM student
WHERE SId in (
SELECT
SId
FROM sc
GROUP BY SId
HAVING count(*) = (SELECT COUNT(*) FROM course));

40. 查询各学生的年龄,只按年份计算

-- 40. 查询各学生的年龄,只按年份计算

-- 关键词,“年龄”, “按年份计算”

-- 1st, 锁定表,学生表

-- 2nd, 使用now(),year()函数计算年龄

SELECT YEAR('1990-01-01 00:00:00');
SELECT NOW();

SELECT
*,
(YEAR(NOW()) - YEAR(Sage)) AS age
FROM student;

41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

-- 41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

-- 关键词,“年龄”,“当前月日<出生年月的月日则,年龄减一”

-- 1st, 锁定表,学生表

-- 2nd, 使用now(),timestamdiff()函数计算年龄

-- timestamdiff()日期相减函数的用法
SELECT TIMESTAMPDIFF(YEAR, '1990-02-01 00:00:00', '2020-01-01 00:00:00');
SELECT TIMESTAMPDIFF(YEAR, '1990-02-01 00:00:00', '2020-04-01 00:00:00');
SELECT TIMESTAMPDIFF(DAY, '1990-02-01 00:00:00', '2020-03-01 00:00:00');
SELECT TIMESTAMPDIFF(HOUR, '1990-02-01 00:00:00', '2020-01-02 00:00:00');

SELECT
*,
TIMESTAMPDIFF(YEAR, Sage, NOW())
FROM student;

42. 查询本周过生日的学生

-- 42. 查询本周过生日的学生

-- 关键词, "周数"

-- 1st, 锁定表,学生表

-- 2nd, 使用week()函数查询
SELECT WEEK('1990-8-14 00:00:00');

SELECT * FROM student;


SELECT
*,
WEEK(Sage),
WEEK(NOW())
FROM student
WHERE WEEK(Sage)=week(NOW());

43. 查询下周过生日的学生

-- 43. 查询下周过生日的学生

-- 关键词,“周数”

-- 1st, 锁定表,学生表

-- 2nd, 使用week()函数查询
SELECT
*,
WEEK(Sage),
WEEK(NOW())+1
FROM student
WHERE WEEK(Sage)=week(now())+1;

44. 查询本周过生日的学生

-- 44. 查询本周过生日的学生

-- 关键词,“月份”

-- 1st, 锁定表,学生表

-- 2nd, 使用month()函数查询

SELECT
*,
MONTH(Sage),
MONTH(NOW())
FROM student
WHERE MONTH(Sage)=MONTH(NOW());

45. 查询下月过生日的学生

-- 45. 查询下月过生日的学生

-- 关键词,“月份”

-- 1st, 锁定表,学生表

-- 2nd, 使用month()函数查询
SELECT
*,
MONTH(Sage),
MONTH(NOW())+1
FROM student
WHERE MONTH(Sage)=MONTH(NOW())+1;

参考链接- bilibili-数据蛙-数据分析面试必备,45道SQL题目
参考链接- Mysql_45道练习题

上一篇:【自用】Python常用数值、数学操作总结


下一篇:shell脚本中的变量赋值