练习1:简单查询(练习1的所有题目自己独立完成,没有问题)
1.1 查询姓“猴”的学生名单
1.2 查询姓名中最后一个字是猴的学生名单(为了验证,临时把学号0002的名字从“猴子”改为了“孙猴”)
1.3 查询姓名中带“猴”的学生名单(同样,为了验证,临时把学号0002的名字从“猴子”改为了“孙猴”)
1.4 查询姓“孟”老师的个数
练习2 汇总分析(练习2的所有题目自己独立完成,没有问题)
汇总分析
2.1 查询课程编号为“0002”的总成绩
2.2 查询选了课程的学生人数
练习:分组
2.3 查询各科成绩最高和最低的分
2.4 查询每门课程被选修的学生数
2.5 查询男生、女生人数
练习:分组结果的条件
2.6 查询平均成绩大于60分学生的学号和平均成绩
2.7 查询至少选修两门课程的学生学号
2.8 查询同名同姓学生名单并统计同名人数(为了验证运行结果,临时把student表里的“马云”改为了“王思聪”)
2.9 查询不及格的课程并按课程号从大到小排列(由于score表不含不及格的成绩,此处临时用score2如下)
score2:
相比猴子老师给出的sql语句,我写的sql语句中用distinct函数去除了重复的课程号,去除重复值也可以通过下面的group by 语句实现:
2.10 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
2.11 查询课程编号为“0004”且分数小于60的学生学号,结果按分数降序排列
此题用score3:
sql语句:
2.12 统计每门课程的学生选修人数(超过2人的课程才统计)要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排序
此处也临时用上一题用的score3
2.13 查询两门以上不及格课程的学生学号,以及不及格课程的平均成绩
仍用上面两个题用的score3
练习3 复杂查询(练习3的部分题目做不出来,看了猴子老师的部分分析思路才做出来,所以要重视)
3.1 查询所有课程成绩小于60分学生的学号、姓名
用score4:
为了验证结果,临时把student表里“王思聪”的学号改为“0005”
sql语句及运行结果如下:
分析:这道题目开始做不出来,是看了猴子老师的部分分析思路后才做出来的,原因一是我对having子句的作用没有真正理解。having子句是对分组结果指定条件,即可以在分组之后的结果中,通过设定条件进行筛选,得到需要的组。这个条件也可以是在having子句中进行的运算。比如此题,就是先对学号分组,然后在having子句中用条件“max(成绩)<60”来筛选出最大成绩小于60的学号。原因二是,我没有敏锐地意识到:如果查询条件不是现成的,而是要从表中通过计算获得的,就要用到子查询。比如这个题,符合条件的学号是要通过“运算”从表中获得的,那么就要用到子查询。
3.2 查询没有学全所有课程的学生的学号、姓名
这个题用原course和student,score表
分析这个题目:第一,这道题刚开始我也没做出来,整道题卡在一点上:如何对比一个学生所学课程是否是全部课程,我的思路误区在于试图用一个学生学习的课程号和所有课程号进行对比,看了猴子老师的分析,才恍然大悟:只需要对比数量就可以了啊,所以迎刃而解。这个思路误区要注意,对以后有启示。第二,这道题用了两个嵌套的select语句,即两个嵌套的子查询。虽然猴子在前面说过避免使用多层嵌套的子查询(因为会使得sql语句难看懂,不好维护和性能变差)。但是这个题目的确需要用到,所以就用了,所以可见要具体情况具体分析,不要死守一般原则而限制解题思路。
3.3 查询出只选修了两门课程的全部学生的学号和姓名!
3.4 1990年出生的学生名单
我在查询结果中加入了“出生日期”这列,以确认具体的出生日期。如果按题目要求,其实可以不显示此列数据。
topN问题:
类型一:分组取每组最大值、最小值,每组最大的N条(topN)记录
3.5 按课程号分组取成绩最大值所在行的数据
3.6 按课程号分组取成绩最小值所在行的数据
3.7 查询各科成绩前两名的记录
分析:这个题我尝试用关联子查询来写,但是怎么都做不出来,看了猴子老师给的答案,觉得这样的sql语句的确是可以得到查询结果,但是如果课程号很多呢,即类别很多呢,有没有更好的办法呢?
练习4 多表查询(所有题目自己都可以做出来,但是最好再熟悉一下。另外,虽然思路都没有问题,但是实际写sql语句时还是会有各种小细节的错误,要更细心)
4.1 不是近视眼的学生都有谁?
“学生表“和”近视学生表“分别如下:
sql语句及运行结果如下:
分析:分析问题的思路是关键!要分析到问题的本质,把实际的业务问题往我们学的sql的各种联结上“靠”。只要涉及多张表的查询,就要想到会用到多表联结。对于这个题目,参考sql联结那张总结表,这个题目的实质是要查找在“学生表”里但是不在“近视学生表”里的数据,即左联结加where 子句。
4.2 对上一题举一反三,题目如下:
sql语句如下:(因为这个问题我已经掌握,为了节省时间没有建立表,只写出了对应的sql语句)
练习:联结
4.3 查询所有学生的学号、姓名、选课数、总成绩
这道题可以参照第五关作业。
思路:先用左联结得到总表,再通过计算得到要查询的结果。
4.4 查询平均成绩大于85的所有学生的学号、姓名和平均成绩
4.5 查询学生的选课情况:学号、姓名、课程号、课程名称
student表和score表我用了left join。(猴子老师用了inner join)参考第五关本题的分析
4.6 查询出每门课程的及格人数和不及格人数
为了方便验证运行结果,本题用score2表,如下:
sql语句及运行结果如下:
其实,这个sql语句,完全可以不用case表达式,这样写出来的sql语句更简洁,运行结果完全一样:
4.7 使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计:各分数段人数,课程号和课程名称
与上一个题比较,这个题就必须用到case表达式。
这个题参考第五关作业该题的分析。为了让分组后的名称更能一眼看出分数范围,我没有用题目给的列的命名,用了数学的区间符号。
4.8 查询课程编号为0003且课程成绩在80分以上的学生的学号和姓名
4.9 如何实现表的行列互换
猴子老师给的解题思路:
第1步:使用常量列输出目标表的结构
第2步:使用case表达式,替换常量列为对应的成绩
注意:下面方框中的两种写法是等价的,哈哈
在这个查询结果中,每一行表示了某个学生的某一门课程的成绩。
每个学生选修某门课程的成绩在下图的每个方块内。可以通过分组取出每门课程的成绩。
第3步:分组
分组,并使用最大值函数max取出上图每个方块里的最大值
但是这儿还有个问题:上面红框中学号0002的学生的课程0001的成绩是0,会让人以为他得了0分,实际情况是他并没有选修这门课程。这个问题要怎么解决呢?
练习5 如何提高sql查询效率
数据量大时,不同的sql语句消耗的时间相差很大,写SQL语句时需要注意以下几点以提高查询效率:
1,select子句中尽量避免使用*。因为*是返回全部数据的意思。
2,where子句比较符号的左侧避免使用函数。因为这会导致数据库引擎进行全表扫描。
如果需要使用函数,将其转化写在比较符号的右侧。
3,避免使用in和not in。这也会导致数据库引擎进行全表扫描,增加运行时间。
遇到要用的情况时,尽量用别的运算符等价代替。
4,尽量避免使用or。这也会导致数据库引擎进行全表扫描。
遇到要用的情况,尽量用别的运算符等价代替。即使写的sql语句长点,只要能缩短运行时间,就是可取的。
5,用limit子句限制返回的数据行数。
平时使用时就养成这样的意识和习惯。