如果FROM关键字后有超过2个以上(含2个)的表参与连接操作,则该查询可以称为连接查询,也可以叫多表查询。
连接查询是SQL语言中最基本的操作,它的本质是多个表之间做笛卡儿积,借由这个思想又衍生出自然连接、θ连接等。
为了方便描述连接操作的结果,下面给出t1、t2、t3几个基本表以及它们的数据作为示例:
t1:
| C1 | C2 |
| 1 | 2 |
| 1 | NULL |
| 2 | 2 |
t2:
| C1 | C2 |
| 1 | 2 |
| 1 | 1 |
| NULL | 2 |
t3:
| C1 | C2 |
| 1 | 1 |
| 1 | 2 |
通常的多表连接可以通过如下形式来实现,具体语句如下:
SELECT projection FROM t1, t2, t3… WHERE selection;
例2-19:t1、t2、t3三个表做连接操作,通过“,”间隔3个基本表t1、t2、t3,这3个表位于FROM关键字的后面,表示需要这3个表做连接操作,具体语句如下:
SELECT * FROM t1, t2, t3 WHERE t1.c1 = 0;
如果两个基本表确定做笛卡儿积操作,则可以在SQL中显式的指定做笛卡儿积的关键字。
例2-20:对表t1、t2做笛卡儿积,如图2-2所示。

图2-2 笛卡儿积示意图
具体语句如下:
SELECT * FROM t1 CROSS JOIN t2;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | 2 | 1 | 1
1 | 2 | | 2
1 | | 1 | 2
1 | | 1 | 1
1 | | | 2
2 | 2 | 1 | 2
2 | 2 | 1 | 1
2 | 2 | | 2
(9 rows)
连接操作还能指定连接条件,如果连接条件中是等值条件,那么这种连接可以称为等值连接。
例2-21:对表t1、t2做等值内连接,如图2-3所示。

图2-3 等值内连接示意图
具体语句如下:
SELECT * FROM t1 INNER JOIN t2 ON t1.c1 = t2.c1;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | 2 | 1 | 1
1 | | 1 | 2
1 | | 1 | 1
(4 rows)
在等值连接的基础上,还衍生出来一种新的连接方式:自然连接。如果进行连接的两个基本表中有相同的属性,那么自然连接会在这些相同的属性上自动做等值连接,而且会自动去掉重复的属性,而等值连接会保留两个表中重复的属性。
例2-22:对表t1、t2做自然连接,如图2-4所示。

图2-4 自然连接示意图
具体语句如下:
SELECT * FROM t1 NATURE JOIN t2;
c1 | c2
----+----
1 | 2
(1 row)
另外从连接结果的角度来划分,连接又可以分为内连接(Inner Join)、外连接(Outer Join)、半连接(Semi Join),如表2-7所示。
表2-7 基本表的数据组织形式
| 名称 | 描述 |
| 内连接 | 只有符合连接条件的结果才会作为最终的连接结果 |
| 外连接 | 又可以分为左外连接(Left Outer Join)、右外连接(Right Outer Join)和全连接(Full Outer Join); 其中左外连接不但显式符合连接条件的结果,而且对于外表(左表)中不符合连接条件的元组也会生成连接结果,由于这些元组在内表(右表)中没有符合连接条件的元组,因此在投影时,对内表的投影为NULL值; 同理,右外连接显式的是内表(右表)中不符合连接条件的元组,全连接则同时显示内表(左表)和内表(右表)中的元组 |
| 半连接 | SQL语法中不能直接使用半连接,通常数据库的优化器会将连接条件中的子查询提升成连接操作,这时候连接的方式就是半连接; 基于连接条件谓词中是否含有否定谓词,半连接还可以分为Semi Join和Anti-Semi Join |
例2-23:对表t1、t2做等值内连接,如图2-5所示。

图2-5 等值内连接示意图
具体语句如下:
SELECT * FROM t1 INNER JOIN t2 ON t1.c1 = t2.c1;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | 2 | 1 | 1
1 | | 1 | 2
1 | | 1 | 1
(4 rows)
例2-24:对表t1、t2做等值左外连接,如图2-6所示。

图2-6 等值左外连接示意图
具体语句如下:
SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | 2 | 1 | 1
1 | | 1 | 2
1 | | 1 | 1
2 | 2 | |
(5 rows)
例2-25:对表t1、t2做等值右外连接,如图2-7所示。

图2-7 等值右外连接示意图
具体语句如下:
SELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 = t2.c1;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | | 1 | 2
1 | 2 | 1 | 1
1 | | 1 | 1
| | | 2
(5 rows)
例2-26:对表t1、t2做等值全连接,如图2-8所示。

图2-8 等值全连接示意图
具体语句如下:
SELECT * FROM t1 FULL JOIN t2 ON t1.c1 = t2.c1;
c1 | c2 | c1 | c2
----+----+----+----
1 | 2 | 1 | 2
1 | 2 | 1 | 1
1 | | 1 | 2
1 | | 1 | 1
| | | 2
2 | 2 | |
(6 rows)
例2-27:对表t1、t2做Semi Join,对于t1中的每一个元组中的t1.c1,都去t2表中探测有没有和其相等的t2.c1,如果能找到就代表符合条件,和普通的连接不同的是,只要找到第一个和其相等的t2.c1就,就代表满足连接条件,如图2-9所示。

图2-9 Semi Join示意图
具体语句如下:
SELECT * FROM t1 WHERE t1.c1 IN (SELECT t2.c1 FROM T2);
QUERY PLAN
-----------------------------------------------------------------
Hash Semi Join
Hash Cond: (t1.c1 = t2.c1)
-> Seq Scan on t1
-> Hash
-> Seq Scan on t2
c1 | c2
----+----
1 | 2
1 |
(2 rows)
例2-28:对表t1、t2做Anti-Semi Join,和Semi Join相对应,t1.c1在t2表中只要找到一个相等的t2.c1,就不满足连接条件,如图2-10所示。

图2-10 Anti-Semi Join示意图
具体语句如下:
SELECT * FROM t1 WHERE t1.c1 NOT IN (SELECT t2.c1 FROM T2 WHERE t2.c1 IS NOT NULL);
QUERY PLAN
------------------------------------------------------------------------
Nested Loop Anti Join
Join Filter: ((t1.c1 = t2.c1) OR (t1.c1 IS NULL) OR (t2.c1 IS NULL))
-> Seq Scan on t1
-> Materialize
-> Seq Scan on t2
Filter: (c1 IS NOT NULL)
c1 | c2
----+----
2 | 2
(1 row)




