1.查询“01”课程比“02”课程成绩高的学生的信息及课程分数
解题思路:
分析题目的关键字,“学生信息”、“课程分数”、“课程编号”
第一步:锁定使用表,学生表、成绩表,这两张表能提供题目所有所需信息
第二步:通过Sid主键连接学生表和成绩表
第三步:进行同一学生不同成绩比较,那么就还需要再连接一个成绩表,利用Sid相同,Cid不同进行关联
第四步:最终回到题目,只需要筛选一下课程,利用WHERE比较分数即可
--解法1
SELECT *
FROM student AS a
INNER JOIN sc AS b
ON a.SId = b.SId
INNER JOIN sc AS c
ON a.SId = c.SId AND b.CId = '01' AND c.CId = '02'
WHERE b.score > c.score;
--解法2
SELECT a.*, b.score_01, b.score_02
FROM Student AS a
INNER JOIN(SELECT a.SId,a.score AS score_01, b.score AS score_02
FROM SC AS a
INNER JOIN SC AS b
ON a.SId = b.SId AND a.CId = '01' AND b.CId = '02'
WHERE a.score > b.score)AS b
ON a.SId = b.SId;
结果展示:
解法1
解法2
1.1查询同时存在“01”课程和“02”课程的情况
解题思路:
分析题目的关键字词,“课程编号”、“同时存在”
第一步:锁定所需要的表,成绩表SC
第二步:需要用到INNER JOIN,实现1名学生的2门课程在同一行,左边的Cid等于“01”课程,右边的Cid等于“02”课程
SELECT *
FROM (SELECT * FROM sc WHERE CId = '01') AS a
INNER JOIN (SELECT * FROM sc WHERE CId = '02') AS b
ON a.SId = b.SId;
第三步:简化,不用子查询
SELECT *
FROM sc AS a
INNER JOIN sc AS b
ON a.SId = b.SId
WHERE a.CId = '01' AND b.CId = '02';
结果展示:
1.2查询存在“01”课程但可能不存在“02”课程的情况(不存在时显示为null)*
解题思路:
分析题目:与上题类似,但限制条件是“01”课程必须有,而“02”课程不必须
第一步:锁定需要表,成绩表SC
第二步:需要用到LEFT JOIN,实现1名学生的2门课程在同一行,而且左边Cid等于“01”课程,右边Cid等于“02”课程
SELECT *
FROM (SELECT * FROM sc WHERE CId = '01') AS a
LEFT JOIN sc AS b
ON a.SId = b.SId AND b.CId = '02';
第三步:简化,不用子查询
SELECT *
FROM sc AS a
LEFT JOIN sc b
ON a.Sid = b.Sid AND b.Cid = '02'
WHERE a.Cid = '01';
结果展示:
1.3查询不存在“01”课程但存在“02”课程的情况
解题思路:
分析题目:限制条件是“01”课程必须不存在、“02”课程必须存在,直接用WHERE实现即可
第一步:锁定需要表,成绩表SC
第二步:筛选出存在“01”课程的学生
SELECT Sid FROM sc WHERE Cid = '01';
第三步:使用NOT IN 筛选出不存在“01”课程、但是存在“02”课程的学生
SELECT *
FROM sc
WHERE Sid NOT IN (SELECT Sid FROM sc WHERE Cid = '01') AND Cid = '02';
结果展示:
2.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
解题思路:
分析题目的关键词,“学生编号”、“学生姓名”、“平均成绩>=60”
第一步:锁定使用表,学生表、成绩表,这两张表能提供题目所有所需信息
第二步:成绩表按照Sid聚合,获取平均成绩,并且筛选出平均成绩>=60的Sid和平均成绩
SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId
HAVING AVG(score) >= 60;
第三步:利用INNER JOIN 连接学生表,获取学生姓名
SELECT a.SId,a.Sname,avg_score
FROM student AS a
INNER JOIN (SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId
HAVING AVG(score) >= 60) AS b
ON a.SId = b.SId;
结果展示:
3.查询在SC表存在成绩的学生信息
解题思路:
分析题目关键词,“SC表”、“成绩”、“学生信息”
第一步:锁定表,学生表、成绩表
第二步:以成绩表为主,左连接学生表,连接主键Sid,使用LEFT JOIN
SELECT b.*
FROM sc AS a
LEFT JOIN student AS b
ON a.SId = b.SId;
第三步:使用GROUP BY,从成绩表中取出唯一Sid,左连接学生表
--第三步
SELECT b.*
FROM (SELECT SId FROM sc GROUP BY SId) AS a
LEFT JOIN student AS b
ON a.SId = b.SId;
--另一种解法
SELECT a.*
FROM Student AS a
INNER JOIN (SELECT DISTINCT SId
FROM SC
WHERE score IS NOT NULL)AS b
ON a.SId = b.SId;
结果展示:
4.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为null)*
解题思路:
分析题目的关键词,“学生信息”、“选课总数”、“所有课程总成绩”
第一步:锁定表,学生表、成绩表
第二步:在SC表中对Sid进行聚合,获取每个学生的选课总数、所有课程总成绩
SELECT SId,COUNT(CId) AS ct,SUM(score) AS sum_score
FROM sc
GROUP BY SId;
第三步:学生表为主表,与第二步得到的成绩汇总进行左连接
SELECT a.SId,a.Sname,b.ct,b.sum_score
FROM student AS a
LEFT JOIN (SELECT SId,COUNT(CId) AS ct,SUM(score) AS sum_score
FROM sc
GROUP BY SId) AS b
ON a.SId = b.SId;
结果展示:
4.1查有成绩的学生信息
解题思路:
第一步:锁定表,学生表、成绩表
第二步:筛选出有成绩的Sid
SELECT SId
FROM sc
GROUP BY SId;
第三步:利用有成绩的Sid对Student表做筛选
SELECT *
FROM student
WHERE SId IN(SELECT SId FROM sc GROUP BY SId);
结果展示:
扩展解法:
--解法1
SELECT *
FROM Student
WHERE SId IN(SELECT DISTINCT SId
FROM SC
WHERE score IS NOT NULL);
--解法2
SELECT a.*
FROM Student AS a
INNER JOIN (SELECT DISTINCT SId
FROM SC
WHERE score IS NOT NULL)AS b
ON a.SId = b.SId;
5.查询[李]姓老师的数量
解题思路:
分析题目关键词,“老师”、“李”、“数量”
第一步:锁定表,教师表
第二步:筛选出[李]姓老师(提示:使用“LIKE”,“%”代表占位符)
SELECT *
FROM teacher
WHERE Tname LIKE '李%';
第三步:统计[李]姓老师的数量
SELECT COUNT(*)
FROM teacher
WHERE Tname LIKE '李%';
结果展示:
6.查询学过[张三]老师授课的同学的信息
解题思路:
分析题目的关键词,“教师姓名”、“学生信息”
第一步:锁定表,教师表、课程表、成绩表、学生表全部要用
第二步:关联课程表和教师表,得到课程Cid与教师Tname的关系
SELECT a.*,Tname
FROM course AS a
INNER JOIN teacher AS b
ON a.TId = b.TId;
第三步:与成绩表关联,得到学生Sid与教师Tname的关系
SELECT a.*,Tname
FROM sc AS a
INNER JOIN (SELECT a.*,Tname
FROM course AS a
INNER JOIN teacher AS b
ON a.TId = b.TId) AS b
ON a.CId = b.CId;
第四步:与学生表关联,获取学生信息
SELECT a.*,Tname
FROM student AS a
INNER JOIN (SELECT a.*,Tname
FROM sc AS a
INNER JOIN (SELECT a.*,Tname
FROM course AS a
INNER JOIN teacher AS b
ON a.TId = b.TId) AS b
ON a.CId = b.CId) AS b
ON a.SId = b.SId;
第五步:增加筛选条件,Tname为[张三]
SELECT a.*,Tname
FROM student AS a
INNER JOIN (SELECT a.*,Tname
FROM sc AS a
INNER JOIN (SELECT a.*,Tname
FROM course AS a
INNER JOIN teacher AS b
ON a.TId = b.TId) AS b
ON a.CId = b.CId) AS b
ON a.SId = b.SId
WHERE Tname = '张三';
结果展示:
-- 另一解法
SELECT a.*,d.Tname
FROM student AS a
INNER JOIN sc AS b
ON a.SId = b.SId
INNER JOIN course AS c
ON b.CId = c.CId
INNER JOIN teacher AS d
ON c.TId = d.TId
WHERE Tname = '张三';
7.查询没有学全所有课程的同学的信息
解题思路:
分析题目的关键词,“同学信息”、“所有课程”
第一步:锁定表,学生表、成绩表、课程表
第二步:根据课程表,获取全部课程总数
SELECT COUNT(CId) FROM course;
第三步:根据成绩表,获取每个学生的所学课程总数,并筛选出所学课程总数小于全部课程总数的学生Sid
SELECT SId,COUNT(CId) AS ct
FROM sc
GROUP BY SId
HAVING ct < (SELECT COUNT(CId) FROM course);
第四步:关联学生表,获取学生信息
SELECT a.*,ct
FROM student AS a
INNER JOIN (SELECT SId,COUNT(CId) AS ct
FROM sc
GROUP BY SId
HAVING ct < (SELECT COUNT(CId) FROM course)) AS b
ON a.SId = b.SId;
结果展示:
8.查询至少有一门课与学号为“01”的同学所学相同的同学的信息
解题思路:
分析题目关键词,“学生信息”、“课程”
第一步:锁定表,成绩表、学生表
第二步:根据成绩表,获取“01”同学所学课程编号
SELECT CId
FROM sc
WHERE SId = '01';
第三步:使用IN,获取课程编号在“01”同学所学课程编号范围内的记录
SELECT *
FROM sc
WHERE CId IN(SELECT CId
FROM sc
WHERE SId = '01');
第四步:关联学生表,获取学生信息
SELECT DISTINCT a.*
FROM student AS a
INNER JOIN (SELECT *
FROM sc
WHERE CId IN(SELECT CId
FROM sc
WHERE SId = '01')) AS b
ON a.SId = b.SId;
结果展示:
9.查询和“01”号的同学学习的课程完全相同的其他同学的信息*
解题思路:
分析题目关键词,“学生信息”、“课程”、“完全相同”
这里的“完全相同”有2个含义:
- 没有学习“01”号同学学习课程以外的其他课程
- 与“01”号同学学习课程数量相等
第一步:锁定表,学生表、成绩表
第二步:找出学了“01”号同学学习课程以外其他课程的同学
SELECT SId
FROM sc
WHERE CId NOT IN (SELECT CId
FROM sc
WHERE SId = '01');
第三步:排除第二步找到的同学以及“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;
第四步:筛选出与“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');
第五步:关联学生表,获取学生信息
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')) AS a
INNER JOIN student AS b
ON a.SId = b.SId;
结果展示:
10.查询没学过“张三”老师讲授的任一门课程的学生姓名
解题思路:
分析题目关键词,“学生姓名”、“张三老师”
第一步:锁定表,4张表
第二步:关联课程表和教师表,筛选出张三老师讲授课程的Cid
SELECT *
FROM course AS a
INNER JOIN teacher AS b
ON a.TId = b.TId
WHERE Tname = '张三';
第三步:关联成绩表,获取学过张三老师课程的Sid
SELECT SId
FROM sc AS a
LEFT JOIN course AS b
ON a.CId = b.CId
INNER JOIN teacher AS c
ON b.TId = c.TId
WHERE Tname = '张三';
第四步:关联学生表,使用NOT IN,筛选出没有学过“张三”老师课程的Sid
SELECT Sname
FROM student AS a
WHERE SId NOT IN (SELECT SId
FROM sc AS a
LEFT JOIN course AS b
ON a.CId = b.CId
INNER JOIN teacher AS c
ON b.TId = c.TId
WHERE Tname = '张三');
展示结果:
-- 另一解法
SELECT Sname
FROM student
WHERE Sid NOT IN(SELECT Sid
FROM sc
WHERE Cid IN(SELECT Cid
FROM course
WHERE Tid IN(SELECT Tid
FROM teacher
WHERE Tname = '张三')));
11.查询两门及以上不及格课程的同学的学号,姓名及其平均成绩
解题思路:
分析题目关键词,“学号姓名”、“平均成绩”、“课程”
第一步:锁定表,学生表、成绩表
第二步:求同学的平均成绩
SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId;
第三步:找出有两门及以上不及格课程的同学
SELECT SId
FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2;
第四步:结合第二步和第三步,求有两门及以上不及格课程的同学的平均成绩
SELECT a.SId,AVG(score) AS avg_score
FROM sc AS a
INNER JOIN(SELECT SId
FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2) AS b
ON a.SId = b.SId
GROUP BY a.SId;
第五步:关联学生表,获取学生姓名
SELECT c.SId,d.Sname,avg_score
FROM(SELECT a.SId,AVG(score) AS avg_score
FROM sc AS a
INNER JOIN(SELECT SId
FROM sc
WHERE score < 60
GROUP BY SId
HAVING COUNT(CId) >= 2) AS b
ON a.SId = b.SId
GROUP BY a.SId) AS c
LEFT JOIN student AS d
ON c.SId = d.SId;
结果展示:
-- 另一解法
SELECT a.Sid,a.Sname,AVG(c.score) AS avg_score
FROM student AS a
INNER JOIN (SELECT Sid,COUNT(Cid)AS num
FROM sc
WHERE score < 60
GROUP BY Sid
HAVING num >= 2)AS b
ON a.Sid = b.Sid
INNER JOIN sc AS c
ON b.Sid = c.Sid
GROUP BY a.Sid;
12.检索“01”课程分数小于60分,按分数降序排列的学生信息
解题思路:
分析题目关键词,“学生信息”、“课程信息”、“降序”
第一步:锁定表,学生表、成绩表
第二步:筛选“01”课程分数小于60的Sid
SELECT SId,score
FROM sc
WHERE CId = '01' AND score < 60;
第三步:关联学生表,获取学生信息,并且按照分数降序排列
SELECT b.*,a.score
FROM(SELECT SId,score
FROM sc
WHERE CId = '01' AND score < 60) AS a
LEFT JOIN student AS b
ON a.SId = b.SId
ORDER BY a.score DESC;
结果展示:
13.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩*
解题思路:
分析题目关键词,“所有学生”、“所有课程”、“平均成绩”
第一步:锁定使用表,学生表、成绩表
第二步:获取所有学生的所有课程成绩(学生左连接成绩表,没有成绩显示null)
SELECT a.SId,b.CId,b.score
FROM student AS a
LEFT JOIN sc AS b
ON a.SId = b.SId;
第三步:求学生的平均成绩
SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId;
第四步:给每条成绩记录加上平均成绩,最终按照平均成绩降序排列
SELECT a.SId,a.CId,a.score,avg_score
FROM(SELECT a.SId,b.CId,b.score
FROM student AS a
LEFT JOIN sc AS b
ON a.SId = b.SId) AS a
LEFT JOIN (SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId) AS b
ON a.SId = b.SId
ORDER BY b.avg_score DESC;
结果展示:
14.查询各科成绩最高分、最低分和平均分,以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,及格为:>=60,中等为:[70,80),优良为:[80,90),优秀为:>=90;要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列*
解题思路:
分析题目:课程号、课程名称、聚合计算(选修人数,最高分,最低分,平均分,及格率,中等率,优秀率,优良率)、排序
第一步:确定使用表,成绩表、课程表
第二步:聚合计算(使用条件判断语句 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;
第三步:排序(按照选修人数降序,课程号升序排列)
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;
第四步:关联课程表,获取cname
SELECT a.*,b.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) AS a
LEFT JOIN course AS b
ON a.CId = b.CId;
结果展示:
15.按各科成绩进行排序,并显示排名,Score重复时也继续排名*
解题思路:
使用窗口函数
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CId ORDER BY score DESC) AS 排名
FROM sc;
15.1按各科成绩进行排序,并显示排名,Score重复时合并名次*
解题思路:
使用窗口函数rank()
SELECT *,
RANK() OVER (PARTITION BY CId ORDER BY score DESC) AS 排名
FROM sc;
使用窗口函数dense_rank()
SELECT *,
DENSE_RANK() OVER (PARTITION BY CId ORDER BY score DESC) AS 排名
FROM sc;