多关系连接查询.
前面我们说过数据库中有多个基本表,各个表中存放着不同的数据。我们前面介绍各种查询操作时的例子也是如此,有学生关系表、教师关系表、课程关系表、选课关系表以及授课关系表等等。用户往往有着使用多个表中的数据来组合、提炼出信息的需求。倘若一个查询过程需要对多个表进行操作,就称之为连接查询。连接查询的结果表称为表之间的连接,连接查询实际上是通过各个表之间共同列的关联性来查询数据的,数据表之间的联系是通过表的字段值来体现的,这种字段称为连接字段。连接操作的目的就是通过加在连接字段上的条件将多个表连接起来,以便从多个表中查询数据。
在关系数据库标准语言SQL与关系数据库管理系统SQL Server(三)中涉及的查询都是针对一个表进行的,当查询同时涉及两个及两个以上的表时,称为连接查询。
连接查询结构.
表与表之间的连接方法有以下两种:
- 表之间满足一定条件的行进行连接时,
FROM
子句指明进行连接的表名,WHERE
子句指明连接的列名及其连接条件。 - 利用关键字
JOIN
进行连接,具体的连接方法分为以下几种:
①【INNER JOIN
】内连接显示符合条件的记录,这也是默认的方法;
②【LEFT (OUTER) JOIN
】左外连接用于显示符合条件的数据行以及左边表中不符合条件的数据行,此时右边数据行会以NULL
来显示。
③【RIGHT (OUTER) JOIN
】右外连接用于显示符合条件的数据行以及右边表中不符合条件的数据行,此时左边数据行会以NULL
来显示。
④【FULL (OUTER) JOIN
】显示符合条件的数据行以及左边表和右边表中不符合条件的数据行,此时缺乏数据的数据行会以NULL
来显示。
⑤【CROSS JOIN
】将一个表的每一个记录和另一个表的每个记录匹配成新的数据行。
另外需要注意,将JOIN
关键字放置于FROM
子句中时,应该有关键字ON
与之对应,来引出连接的条件。
内连接查询.
首先我们给出一个例子,使用不同的方法来实现查询功能:
【例】查询刘伟老师所授课程的课程号并且要求列出刘伟老师的教师号和教师姓名。
方法1:
SELECT T.TNo,TN,CNo
FROM T,TC
WHERE T.TNo=TC.TNo AND TN='刘伟'
这里的T.TNo=TC.TNo
是连接条件,其中TNo
是连接字段,引用该字段时必须要加上表前缀,这是由于T
和TC
表中都有TNo
这一字段,需要表示出区别。TN='刘伟'
就是查询条件,上述查询过程中,将T
表和TC
表中TNo
字段相等的行进行连接,而后再选取TN='刘伟'
的行,最后再对于TNo,TN,CNo
进行投影操作,得到结果。
方法2:
SELECT T.TNo,TN,CNo
FROM T INNER JOIN TC
ON T.TNo=TC.TNo
WHERE TN='刘伟'
方法2和方法1的不同之处其实只是内连接查询的两种写法,后者在FROM
子句中指明要进行连接的表,并且将连接条件放在WHERE
子句中;而前者用JOIN
关键字指明要连接的表,而将连接条件以ON
关键字引出。
方法3(涉及子查询):
SELECT R1.TNo,R2.TN,R1.CNo
FROM
(
SELECT TNo,CNo
FROM TC
) AS R1 INNER JOIN
(
SELECT TNo,TN
FROM T
WHERE TN='刘伟'
) AS R2
ON R1.TNo=R2.TNo
说实话,有点得不偿失,是为了使用子查询而使用了子查询。关于子查询,我们后续会介绍。
【例】查询所有选课学生的学号、姓名、选课名称以及成绩。
SELECT S.SNo,SN,CN,Score
FROM S,C,SC
WHERE S.SNo=SC.SNo AND SC.CNo=C.CNo
本题中涉及了三个表的连接,WHERE
子句中含有两个连接条件。
【例】查询每门课程的课程号、课程名以及选课人数。
SELECT SC.CNo,CN,COUNT(SC.CNo) AS StudentNumber
FROM SC,C
WHERE SC.CNo=C.CNo
GROUP BY SC.CNo,CN
值得注意的是,GROUP BY
子句中,需要按照CNo和CN两个字段进行分组,否则系统会给出报错信息:
选择列表中的列 ‘C.CN’ 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。更多信息,可以参考这篇文章。
外连接查询.
在上面的内连接查询中,无论是FROM...WHERE
形式还是INNER JOIN...ON
形式,都不会输出那些不满足连接条件的元组,我们在【例】查询所有选课学生的学号、姓名、选课名称以及成绩中,由于学号为S6的吴丽同学根本没有选课,所以就不会有她的信息。(提到的关系表以《数据库原理及应用教程》-陈志泊-第4版-第27页为例)。而在外部连接中,参与连接的表有主从之分,以主表的每行数据去匹配从表的数据列。符合连接条件的数据会直接返回到结果集中;而那些不符合连接条件的列,将被填上NULL后,再返回到结果集中(bit型的数据有例外,因为bit不允许有NULL值,所以会被填上0,再返回到结果集中)。
外连接以主表所在的方向进行区分,主表在左边就称为左外部连接;主表在右边就称为右外部连接。
【例】查询所有学生的学号、姓名、选课名称及成绩。(未选课的同学选课信息及成绩显示为NULL)
SELECT S.SNo,SN,CN,Score
FROM S
LEFT OUTER JOIN SC
ON S.SNo=SC.SNo
LEFT OUTER JOIN C
ON SC.CNo=C.CNo
与前面提到的内连接查询做一个对比:
SELECT S.SNo,SN,CN,Score
FROM S,C,SC
WHERE S.SNo=SC.SNo AND SC.CNo=C.CNo
交叉查询.
交叉查询CROSS JOIN
对于连接起来的表没有任何要求。
【例】对学生表S和课程表C进行交叉查询。
SELECT *
FROM S CROSS JOIN C
上述查询的结果是将学生表S中的每一个记录和课程表C中的每一个记录组合成新的数据行,结果集中的元组数是二者之积,列数是二者之和。
自连接查询.
当一个表与其自身进行连接操作时,称为表的自身连接。
【例】查询所有比刘伟老师工资高的教师的姓名、工资以及刘伟老师的工资。
方法1:
SELECT X.TN,X.Sal AS Sal_a,Y.Sal AS Sal_b
FROM T AS X, T AS Y
WHERE Y.TN='刘伟' AND X.Sal>Y.Sal
方法2:
SELECT X.TN,X.Sal AS Sal_a,Y.Sal AS Sal_b
FROM T AS X INNER JOIN T AS Y
ON Y.TN='刘伟' AND X.Sal>Y.Sal
方法3:
SELECT R1.TN,R1.Sal,R2.Sal
FROM
(SELECT TN,Sal FROM T) AS R1
INNER JOIN
(SELECT Sal FROM T WHERE TN ='刘伟') AS R2
ON R1.Sal>R2.Sal