上篇
中篇
下篇
知识要点与易错点总结
在MySQL中,Limit用于指定要返回的记录数量
因为SQL不能Group by以后取Limit,所以为了进行每组内排名,就需要用到窗口函数了,常见使用场景例如:
窗口函数的语法规则如下:
<窗口函数> over (partition by <用于分组的列名> order by <用于排序的列名>)
窗口函数题目整理(完整题目列表见文章最后)
【18. 查询各科成绩前三名的记录】
#保留名次空缺
【15.1 按各科成绩进行排序,并显示排名, 成绩重复时保留名次空缺】
***相比上一题【18. 查询各科成绩前三名的记录】,这里不但需要显示排名,还需要显示各科成绩,所以用窗口函数显示排名是最简单的方法
解法1:窗口函数
#解法1:窗口函数
解法2:表连接查询
如果不用rank函数,写法就相对复杂一点了,下面是思路分析
第一步:初步排名
#初步排名
第二步:加入学生名次
#最终代码
【15.2 按各科成绩进行排序,并显示排名, 成绩重复时合并名次】
***和上一题的区别就是如果有重复成绩,合并名次,即有并列第二时,显示1,2,2,3,4
解法1:窗口函数
#解法1:窗口函数
解法2:表连接
#解法2:表连接
【16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺】
解法1:窗口函数
#解法1:窗口函数
解法2:使用变量
#解法2:使用变量方法1(设置变量myrank初始值)
变量就是一个容器,在需要不断更改的地方放一个变量,而不是固定的值,这样每次需要更改的时候,只需要更改变量的值就可以。这一题解法2中使用变量myrank保存排名的动态变化。
说明一下变量的使用方法:
解法2:使用变量方法1(设置变量myrank初始值)
解法2:使用变量方法2(每次查询都初始化变量myrank)
【36. 查询所有课程成绩第二名到第三名的学生信息及课程成绩】
select
知识要点与易错点总结
什么情况下需要用子查询?
比较运算符
子查询题目整理(完整题目列表见文章最后)
【3. 查询在成绩表存在成绩的学生信息】
【28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)】
***两题思路一致,可以用子查询,也可以用表连接,第28题和第3题解法2的区别就是不加Where筛选成绩非null值的数据(存在学生没成绩,没选课的情况)
解法1:子查询
#解法1:子查询
解法2:表连接
#解法2:表连接
【6. 查询学过"张三"老师授课的同学的信息】
***可以用Where直接多表查询,也可以用子查询,子查询的思路与下一题【10. 查询没学过"张三"老师讲授的任一门课程的学生姓名】相同
select
【10. 查询没学过"张三"老师讲授的任一门课程的学生姓名】
select
【33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及成绩】
#解法1:MAX
select cname, tname, sname, cscore, max(distinct cscore) as 最高分
from student, course, score, teacher
where score.sid = student.sid
and score.cid = course.cid
and teacher.tid = course.tid
and tname = '张三';
#解法2:Limit
select cname, tname, sname, cscore
from student, course, score, teacher
where score.sid = student.sid
and score.cid = course.cid
and teacher.tid = course.tid
and tname = '张三'
order by cscore desc limit 1;
【34. 成绩有重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及成绩】
***和上一题的区别是,如果张三老师所授课程里有多个学生获得并列第一的成绩,需要全部找出来,这时用MAX只能找到其中一个,并且如果不知道到底有几个学生是并列第一的话,也没有办法使用LIMIT。比较好的方式是子查询。
第一步:修改成绩表
#修改成绩表
update score
set cscore = 90
where cid = 02 and sid = 07;
第二步:查询多个02课程最高分
#最终代码
select cname, tname, sname, cscore
from student, course, score, teacher
where score.sid = student.sid
and score.cid = course.cid
and teacher.tid = course.tid
and tname = '张三'
and cscore in
(select max(cscore) as 最高分
from student, course, score, teacher
where score.sid = student.sid
and score.cid = course.cid
and teacher.tid = course.tid
and tname = '张三');
【7. 查询没有学全所有课程的同学的信息】
【39. 查询选修了全部课程的学生信息】
***这里主要解释第7题,第39题的代码与本题解法1里的子查询代码一致
解法1:反向思考
#解法1:反向思考
解法2:表连接
#解法2:表连接方法1
解法2:表连接方法1
解法2:表连接方法2
【8. 查询至少有一门课与学号为"01"的同学所学相同的同学的信息】
select
【9. 查询和"01"号的同学学习的课程完全相同的其他同学的信息】
***这题是上一题【8. 查询至少有一门课与学号为"01"的同学所学相同的同学的信息】的难度提高版,而且网上能查到的答案大多是伪答案,比如说在第8题的基础上再加一个条件找出选课数也和01同学相同的学生,这种解法其实没有真正解决问题。
经过研究发现,group_concat()函数可以解决这个题目的要求,语法规则如下:
group_concat( [distinct] 需要连接的字段 [order by 需要排序的字段 asc/desc] [separator '分隔符'] )
补充:concat_ws() 函数也有把两个字符串连接为一个字符串的效果,但是无法针对分组做处理,另外concat_ws() 函数语法为:concat_ws('分隔符', str1, str2, ...)
第一步:找到所有学生的选课情况
#第一步:找到所有学生的选课情况
第二步:找到01号学生的选课情况
#第二步:找到01号学生的选课情况
第三步:join上面的两个表,连接条件为 选课情况 字段,并去除01号同学的记录
#最终代码
【35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩】
***题目本身有歧义,这里理解为找出选了不止一门课,且自己的不同课程分数相同的学生,比如说一个学生选了01课和03课,且分数都是80
解法1:子查询+自交
#解法1:子查询+自交
解法2:子查询+聚合函数
#解法2:子查询+聚合函数
【2020.07.14 补充题:计算每门课的男女生比例】
看到一个新的题目比较有意思,也用到了子查询,这里也分享一下解法。
select
题目列表:
1.1 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
1.2 查询同时上过"01"课程和"02"课程的学生
1.3 查询上过"01"课程但可能没上过"02"课程的学生 (这种情况显示为 null)
1.4 查询没上过"01"课程,只上过"02"课程的学生
2. 查询平均成绩大于等于 60 分的同学的学生编号、学生姓名和平均成绩
3. 查询在 SC 表存在成绩的学生信息
4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null)
5. 查询「李」姓老师的数量
6. 查询学过张三老师授课的同学的信息
7. 查询没有学全所有课程的同学的信息
8. 查询至少有一门课与学号为"01"的同学所学相同的同学的信息
9. 查询和"01"号的同学学习的课程完全相同的其他同学的信息
10. 查询没学过"张三"老师讲授的任一门课程的学生姓名
11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
12. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
14. 查询各科成绩最高分、最低分和平均分,以如下形式显示:
课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
(及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90)
要求输出课程号和选修人数,查询结果按人数降序排列列,若人数相同,按课程号升序排列
15.1 按各科成绩进行排序,并显示排名, 成绩重复时保留名次空缺
15.2 按各科成绩进行排序,并显示排名, 成绩重复时合并名次
16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
18. 查询各科成绩前三名的记录
19. 查询每门课程被选修的学生数
20. 查询出只选修两门课程的学生学号和姓名
21. 查询男生、女生人数
22. 查询名字中含有「风」字的学生信息
23. 查询同名同性学生名单,并统计同名人数
24. 查询 1990 年年出生的学生名单
25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
26. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
27. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
29. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
30. 查询不及格的课程
31. 查询课程编号为 01 且课程成绩在 80 分及以上的学生的学号和姓名
32. 求每门课程的学生人数
33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
36. 查询所有课程成绩第二名到第三名的学生信息及课程成绩
37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)
38. 检索至少选修两门课程的学生学号
39. 查询选修了全部课程的学生信息
40. 查询各学生的年龄,只按年份来算
41. 按照出生日期来算,如果当前月日 < 出生年月的月日,年龄减一
42. 查询本周过生日的学生
43. 查询下周过生日的学生
44. 查询本月过生日的学生
45. 查询下月过生日的学生