3.4.2 连接查询

3.4.2 连接查询

在通常的查询任务中,用户检索的数据可能不是来源于一个表,例如某用户想要获取某个学生的姓名、课程名以及各科成绩,姓名信息来源于Student表,课程名信息来源于Course表,而成绩信息来源于SC表,这就涉及多个表的连接查询。

1)连接查询概述

连接查询是指通过两个或两个以上的表的连接操作来实现的查询。通常情况下,在进行连接查询时,需要指定连接条件,用来连接两个或多个表的条件称为连接条件或连接谓词。通过连接查询,可以从两个或多个表中根据各个表之间的逻辑关系来检索数据。连接查询是关系数据库中最主要的查询,主要包括内部连接、外部连接和交叉连接。

连接查询的语法可以在WHERE或FROM子句中指定连接条件,因此连接查询的语法格式包括以下两种:

①在WHERE子句中指定连接条件的基本格式为:

说明:

比较运算符主要有:=、>、<、>=、<=、!=、<>等;

各连接属性列的数据类型必须是可比的,但名字不必相同;

②在FROM子句中指定连接条件的基本格式为:

说明:

join_type:指定执行的连接类型,内部连接:[INNER]JOIN;左外连接:LEFT[OUTER]JOIN;右外连接:RIGHT[OUTER]JOIN;完全外部连接:FULL[OUTER]JOIN;交叉连接:CROSS JOIN;

join_conditon:连接条件。

这两种不同格式的查询效率是一样的,SQL Server会给出相同的查询计划。

2)内部连接

内部连接是指根据连接条件对两个或多个表的连接属性列进行比较,将符合连接条件的记录连接起来的一种连接形式。内部连接一般分为等值连接、非等值连接、自身连接等。

(1)等值连接

连接运算符为“=”时,称为等值连接。

【例3.46】 查询每个学生及其选修课程的情况,需列出:学号、姓名、课程号、成绩。

SELECT Student.Sno学号,Sname姓名,Cno课程号,Grade成绩

FROM Student,SC

WHERE Student.Sno=SC.Sno;

SELECT Student.Sno学号,Sname姓名,Cno课程号,Grade成绩

FROM Student INNER JOIN SC ON Student.Sno=SC.Sno;

本例中,SELECT子句和WHERE子句中的Sno属性名前面加上了表名前缀,这是为了避免混淆。如果属性名在参加连接的各表中是唯一的,则可以省略表名前缀。

关系数据库管理系统执行连接操作的过程是:首先在Student中找到第一个元组,然后从头开始扫描SC表,逐一查找与Student表第一个元组的Sno相等的SC元组,找到后就将Student表中的第一个元组与该元组拼接起来,形成结果关系中一个元组。SC表全部查找完后,再找Student表中第二个元组,然后再从头开始扫描SC,逐一查找满足连接条件的元组,找到后就将Student表中的第二个元组与该元组拼接起来,形成结果表中一个元组。重复上述操作,直到Student中的全部元组都处理完毕为止。这就是嵌套循环连接算法的基本思想。

如果在SC表Sno上建立了索引的话,就不用每次全表扫描SC表了,而是根据Sno值通过索引找到相应的SC元组。用索引查询SC中满足条件的元组会比全表扫描快。

【例3.47】 查询每个学生的姓名、选修的课程名及成绩。

SELECT Sname姓名,Cname课程名,Grade成绩

FROM Student,SC,Course

WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno;

连接操作除了可以是两表连接、一个表与其自身连接外,还可以是两个以上的表进行连接,一般称为多表连接。执行多表连接时,通常是先进行两个表的连接操作,再将其连接结果与第三个表进行连接。本例的执行方式:先将Student与SC表进行连接,得到每个学生的学号、姓名、性别、出生日期、所在院系、所选课程号和相应的成绩,然后再将其与Course表进行连接,得到最终结果。

(2)自身连接

如果在一个连接查询中,涉及的两个表都是同一个表,这种查询称为表的自身连接。表的自身连接是一种特殊的内部连接,它是指相互连接的表在物理上为同一个表,但在逻辑上是两个表。使用表的自身连接时,需要给表起别名以示区别,且由于所有属性名都是同名属性,因此属性名前必须使用别名前缀。

【例3.48】 查询每门课程的间接选修课(即选修课的选修课)。

SELECT FIRST.Cno课程号,SECOND.Cpno间接选修课号

FROM Course FIRST,Course SECOND

WHERE FIRST.Cpno=SECOND.Cno;

在Course表中只有每门课程的直接选修课信息,而没有选修课的选修课信息。要得到这个信息,必须先对一门课找到其选修课,再按此选修课的课程号查找它的选修课程。这就要将Course表与其自身连接。为此,要为Course表取两个别名,假设一个是FIRST,另一个是SECOND。

FIRST

SECOND

可能的查询结果为:

(3)非等值连接

在连接条件中使用除“=”运算符以外的其他比较运算符时,是非等值连接。

【例3.49】 查询所有比“刘敏”年龄大的学生姓名、年龄。

一条SQL语句可以同时完成选择和连接查询,这时WHERE子句是由连接谓词和查询谓词组成的复合条件。

3)外部连接

与内部连接不同,外部连接生成的结果集不仅包含符合连接条件的数据记录,还包含左表(左外连接时的表)、右表(右外连接时的表)中所有的数据记录。例如,如果想以Student表为主体列出每个学生的基本情况及其选课情况,即使某个学生没有选课,仍把该学生的元组保存在结果集中,而在SC表的属性上设为空值NULL,这时就可以使用外部连接。

外部连接分为左外连接、右外连接和完全外部连接。

LEFT OUTER JOIN(左外连接):用于显示符合条件的数据记录以及左边表中不符合条件的数据记录,此时右边数据记录会以NULL来显示。

RIGHTOUTER JOIN(右外连接):用于显示符合条件的数据记录以及右边表中不符合条件的数据记录,此时左边数据记录会以NULL来显示。

FULL OUTER JOIN(完全外部连接):用于显示符合条件的数据记录以及左边表和右边表中不符合条件的数据记录,此时缺乏的数据记录会以NULL来显示。

【例3.50】 查询每个学生的选课情况,即使没有选修课程也需列出:学号、姓名、性别、出生日期、所在学院、课程号和成绩。

或者使用右外连接实现:

可能的查询结果为:

4)交叉连接

交叉连接没有连接条件,对两个表做交叉连接返回两个表的笛卡尔积,结果集中的行数为两表行数的积,结果集中的列数为两个表属性列的和。交叉连接实际中很少应用,一是其结果没有实用价值,二是由于其结果集记录太多,需要花费大量的运算时间和高性能设备的支持,但它是所有连接运算的基础。

【例3.51】 Student表和SC表进行交叉连接。

SELECT S.*,SC.*

FROM Student SCROSS JOIN SC;

假设Student表中有m个记录,SC表中有n个记录,则查询结果集中将包含m×n个记录。

注意:CROSS JOIN可以省略,例3.46也可以使用下述语句实现:

SELECT S.*,SC.*

FROM Student S,SC;