T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list ) T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2
INNER 和 OUTER 对所有连接(join) 类型都是可选的.INNER 是缺省; LEFT,RIGHT,和 FULL 隐含外连接.
连接条件在ON或USING子句里声明, 或者用关键字NATURAL隐含地声明.连接条件判断来自两个源表 中的那些行是"匹配"的,这些我们将在下面详细解释.
ON子句是最常见的连接条件的类型∶它接收一个和WHERE子句里用的一样的 布尔值表达式.如果两个分别来自T1和T2的行在ON表达式上运算的 结果为真,那么它们就算是匹配的行.
USING是缩写的概念∶它接收一个用逗号分隔的字段名字列表, 这些字段必须是连接表共有的,最终形成一个连接条件,表示 这些字段对必须相同.最后,JOIN USING 的输出会为每一对相等 的输入字段输出一个字段,后面跟着来自各个表的所有其它字段. 因此,USING (a, b, c) 等效于 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) 只不过是如果使用了ON,那么在结果里 a,b,和 c字段每个都会有两个, 而用USING的时候每个字段就只会有一个.
最后,NATURAL 是USING 的缩写形式∶它形成一个 USING 列表, 该列表由那些在两个表里都出现了的字段名字组成.和USING一样, 这些字段只在输出表里出现一次.
条件JOIN的可能类型是∶
-
INNER JOIN
-
对于 T1 的每一行 R1,生成的连接表都有一行对应 T2 中的 每一个满足和 R1 的连接条件的行.
LEFT OUTER JOIN
-
首先,执行一次内连接.然后,为 T1 里那些和 T2 里任何一行都不满足连接条件的行返回一个连接行, 同时该连接行里对应 T2 的列用空值补齐.因此, 生成的连接表里无条件地包含来自 T1 里的每一行至少 一个副本.
RIGHT OUTER JOIN
-
首先,执行一次内连接.然后,为 T2 里那些和 T1 里任何一行都不满足连接条件的行返回一个连接行, 同时该连接行里对应 T1 的列用空值补齐.因此, 生成的连接表里无条件地包含来自 T2 里的每一行.
FULL OUTER JOIN
-
首先,执行一次内连接.然后,为 T1 里那些和 T2 里任何一行都不满足连接条件的行返回一个连接行, 同时该连接行里对应 T2 的列用空值补齐. 同样,为 T2 里那些和 T1 里的任何行都不满足连接条件的 行返回一个连接行,该行里对应 T1 的列用空值补齐.
如果 T1 和 T2 有一个或者都是可以连接(join)的表, 那么所有类型的连接都可以串在一起或嵌套在一起. 你可以在JOIN子句周围使用圆括弧来控制连接顺序, 如果没有圆括弧,那么JOIN子句是从左向右嵌套的.
为了解释这些问题,假设我们有一个表 t1
num | name -----+------ 1 | a 2 | b 3 | c
和 t2
num | value -----+------- 1 | xxx 3 | yyy 5 | zzz
然后我们用不同的连接方式可以获得各种结果:
=> SELECT * FROM t1 CROSS JOIN t2; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 1 | a | 3 | yyy 1 | a | 5 | zzz 2 | b | 1 | xxx 2 | b | 3 | yyy 2 | b | 5 | zzz 3 | c | 1 | xxx 3 | c | 3 | yyy 3 | c | 5 | zzz (9 rows) => SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy (2 rows) => SELECT * FROM t1 INNER JOIN t2 USING (num); num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 rows) => SELECT * FROM t1 NATURAL INNER JOIN t2; num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 rows) => SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy (3 rows) => SELECT * FROM t1 LEFT JOIN t2 USING (num); num | name | value -----+------+------- 1 | a | xxx 2 | b | 3 | c | yyy (3 rows) => SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy | | 5 | zzz (3 rows) => SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy | | 5 | zzz (4 rows)
用 ON 声明的连接条件也可以包含与连接不直接相关 的条件。这种功能可能对某些查询很有用,但是需要我们仔细想想。 比如:
=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx'; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | | (3 rows)