<>本篇内容继续上篇的查询【2】,表仍然是那三张表。本篇主要总结分组查询(续)、连接查询。依旧采用先展示SQL语句,再展示测试效果的方式。
<>一、GROUP BY子句(续)
where子句与having短语的区别在于作用对象不同,where子句作用域基本表或视图,从中选择满足条件的元组。having短语作用于组,从中选择满足条件的组。
例1:查询平均成绩大于等于86分的学生学号和平均成绩
<>错误的查询语句:
select Sno,avg(Grade) from SC where avg(Grade)>=86 group by Sno;
报错内容为如以下所示,原因就在于where子句中是不能用聚集函数作为条件表达式的
<>正确的查询语句:
select Sno,avg(Grade) from SC group by Sno having avg(Grade)>=86;
<>二、连接查询
连接查询是关系数据库中最主要的查询,包括等值连接查询,自然连接查询,非等值连接查询,自身连接查询,外连接查询和复合条件连接查询等。
<>1.等值与非等值连接查询
连接查询的where子句中用来连接两个表的条件称为连接条件或连接谓词
。其中,当连接于算符为=号时,称为等值连接。使用其他运算符称为非等值连接。连接谓词中的列名称为连接字段。连接条件中的各连接字段类型必须是可比的,但名字不必相同。
例1:查询每个学生及其选修课程的情况
两个表之间的联系是通过公共属性Sno实现的
select Student.*,SC.* from Student,SC where Student.Sno=SC.Sno;
上述中,对属性名都加了表名前缀,避免引起混淆,如果属性名是唯一的,则可以省略。且查询时对Student和SC都加了*号,如果只写一个,可以发现效果是一样的,因为结果的查询是基于SC表的,因为SC表中Sno要么为空要么来自于Student表中存在的Sno
补充数据库管理系统执行该连接操作的一种可能过程,以便更好的理解数据库的内部工作和原理,更加方便记忆:首先在表Student中找到第一个元组,然后从头开始扫描SC表,逐一查询与Student第一个元组的Sno相等的SC元组,找到后就将Student中的第一个元组与该元组拼接起来,形成结果表中一个元组。SC表全部查找完后,再找Student中第二个元组,然后再从头开始扫描,逐一查询满足条件的,反复重复该过程,直到处理完毕为止。这是
嵌套循环连接算法的思想。
上述的算法在查找时运行效率较低,这里再介绍一种更加高效的算法,叫做排序合并法(SORT MERGE)
,简述一下它的原理:首先按连接属性对表进行排序,然后从表1中第一个元组开始,在表2中查找与之连接属性相等的元组,直到不符合为止,此时就停止查找。然后从表1的第二个元组开始,在表2中接着上次的查找继续进行,直到不符合为止。该算法和嵌套循环相比,对表2的遍历查找次数少了很多,第二个只需要一次,而第一个每有一个表1元组,就要遍历一次表2.
例2:对例1用自然连接完成
<>自然连接:在等值连接中把目标列中重复的属性列去掉。
select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade from Student,SC where
Student.Sno=SC.Sno;
与非自然连接的对比如下:
例3:查询选修2号课程且成绩在86分以上的所有学生的学号和姓名
select Student.Sno,Sname from Student,SC where Student.Sno=SC.Sno and SC.Cno=
'2' and SC.Grade>=90;
<>2.自身连接
连接操作不仅可以在两个表之间进行,也可以是一个表与其自己进行连接,称为表的自身连接。
例1:查询每一门课的间接先修课(即先修课的先修课)
由于是对同一个表进行操作,且查找连接条件,这就要求要对表起别名,防止混淆。对Course表起两个别名,一个是Course1,一个是Course2。两张表中的数据一样,其实都是Course表
select Course1.Cno,Course2.Cpno from Course Course1,Course Course2 where
Course1.Cpno=Course2.Cno;
<>3.外连接
在通常的连接操作中,只有满足连接条件的元组才能作为结果输出,不满足的就直接舍弃掉了,这样做可能会舍弃掉一些我们关心的数据,而外连接就可以解决这个问题。外连接一般会选择某个表作为主体,这样输出时,该表中的数据就都会输出(包括连接查询时结果为空的那一行)。
例1:改写查询每个学生及其选修课程的情况
想要查看每个学生的情况,这时以Student表为主表就会比较合适,因此可以使用左连接
select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade from Student left outer join
SCon(Student.Sno=SC.Sno);
可以通过下图查看不同
此外,可以使用USING来去掉结果中的重复值,但在SQL Server中是不允许的,在mysql中可以。
变式:使用右外连接
select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade from Student right outer
join SC on(Student.Sno=SC.Sno);
二者对比如下:上边为左外连接,下边为右外连接
<>4.多表连接
连接操作除了可以是两表连接、一个表与其自身连接外,还可以是两个以上的表进行连接,此时称为多表连接。一般涉及到哪几个表中的数据,就要写几个表,同时要给出连接的条件。
例:查询每个学生的学号、姓名、选修的课程名及成绩
注意,连接条件不要少,否则对应不上
select Student.Sno,Sname,Cname,Grade from Student,SC,Course where Student.Sno=
SC.Sno and SC.Cno=Course.Cno;
虽然是多表操作,涉及多张表,但本质上它还是先进行两个表的连接操作,再将其与第三张表进行连接(前两张表查询的结果表与第三张表,这实际上上也是两张表的连接查询操作,以此类推即可)
<>三、课程感悟
本次实验课内容较为简单,老师讲的也很明白,有的也亲自示范了一遍,所以自己再做起来,并结合着课本上的例子,就会容易很多。虽然查询出意料之中的结果不难,但要记忆的内容仍然很多,如基本格式,还有一些细节,where子句中不能使用聚集函数等,仍然需要加强练习和记忆,希望自己可以学的更好,效率更高!
<>人们常觉得准备的阶段是在浪费时间,只有当真正机会来临,而自己没有能力把握的时候,才能觉悟自己平时没有准备才是浪费了时间。——法国:罗曼·罗兰