Mysql经典45道题(详解1-15)

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';

结果展示:

Mysql经典45道题(详解1-15)_第1张图片

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';

结果展示:

Mysql经典45道题(详解1-15)_第2张图片

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;

Mysql经典45道题(详解1-15)_第3张图片

 第三步:利用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;

 结果展示:

Mysql经典45道题(详解1-15)_第4张图片

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

解题思路:

分析题目关键词,“SC表”、“成绩”、“学生信息”

第一步:锁定表,学生表、成绩表

第二步:以成绩表为主,左连接学生表,连接主键Sid,使用LEFT JOIN

SELECT b.*
FROM sc AS a
LEFT JOIN student AS b
ON a.SId = b.SId;

Mysql经典45道题(详解1-15)_第5张图片

Mysql经典45道题(详解1-15)_第6张图片

 第三步:使用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;

 结果展示:

Mysql经典45道题(详解1-15)_第7张图片

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

解题思路:

分析题目的关键词,“学生信息”、“选课总数”、“所有课程总成绩”

第一步:锁定表,学生表、成绩表

第二步:在SC表中对Sid进行聚合,获取每个学生的选课总数、所有课程总成绩

SELECT SId,COUNT(CId) AS ct,SUM(score) AS sum_score
FROM sc
GROUP BY SId;

Mysql经典45道题(详解1-15)_第8张图片

第三步:学生表为主表,与第二步得到的成绩汇总进行左连接

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;

结果展示:

Mysql经典45道题(详解1-15)_第9张图片

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);

结果展示:

Mysql经典45道题(详解1-15)_第10张图片

扩展解法:

--解法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;

Mysql经典45道题(详解1-15)_第11张图片

第三步:与成绩表关联,得到学生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;

Mysql经典45道题(详解1-15)_第12张图片

Mysql经典45道题(详解1-15)_第13张图片

第四步:与学生表关联,获取学生信息

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;

Mysql经典45道题(详解1-15)_第14张图片

Mysql经典45道题(详解1-15)_第15张图片

第五步:增加筛选条件,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 = '张三';

结果展示:

Mysql经典45道题(详解1-15)_第16张图片

-- 另一解法
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);

Mysql经典45道题(详解1-15)_第17张图片

第四步:关联学生表,获取学生信息 

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;

结果展示:

Mysql经典45道题(详解1-15)_第18张图片

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');

Mysql经典45道题(详解1-15)_第19张图片

Mysql经典45道题(详解1-15)_第20张图片

第四步:关联学生表,获取学生信息 

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;

结果展示:

Mysql经典45道题(详解1-15)_第21张图片

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

解题思路:

分析题目关键词,“学生信息”、“课程”、“完全相同”

这里的“完全相同”有2个含义:

  1. 没有学习“01”号同学学习课程以外的其他课程
  2. 与“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;

Mysql经典45道题(详解1-15)_第22张图片

第三步:找出有两门及以上不及格课程的同学 

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;

Mysql经典45道题(详解1-15)_第23张图片

Mysql经典45道题(详解1-15)_第24张图片

第三步:求学生的平均成绩 

SELECT SId,AVG(score) AS avg_score
FROM sc
GROUP BY SId;

Mysql经典45道题(详解1-15)_第25张图片

第四步:给每条成绩记录加上平均成绩,最终按照平均成绩降序排列 

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;

结果展示:

Mysql经典45道题(详解1-15)_第26张图片Mysql经典45道题(详解1-15)_第27张图片

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;

Mysql经典45道题(详解1-15)_第28张图片

 第三步:排序(按照选修人数降序,课程号升序排列)

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;

Mysql经典45道题(详解1-15)_第29张图片

第四步:关联课程表,获取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;

 结果展示:

Mysql经典45道题(详解1-15)_第30张图片

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

解题思路:

使用窗口函数

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

Mysql经典45道题(详解1-15)_第31张图片

15.1按各科成绩进行排序,并显示排名,Score重复时合并名次* 

解题思路:

使用窗口函数rank()

SELECT *,
       RANK() OVER (PARTITION BY CId ORDER BY score DESC) AS 排名
FROM sc;

Mysql经典45道题(详解1-15)_第32张图片

使用窗口函数dense_rank()

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

Mysql经典45道题(详解1-15)_第33张图片

你可能感兴趣的:(#,SQL题集,mysql,数据库)