"INNER JOIN" 和 "OUTER JOIN" 有什么区别?
"INNER JOIN" 和 "OUTER JOIN" 有什么区别?
此外,LEFT OUTER JOIN
,RIGHT OUTER JOIN
和 FULL OUTER JOIN
是如何安排的?
对我来说,维恩图并没有什么用处。
它们没有显示交叉联接和内部联接之间的区别,例如,或者更普遍地显示任何不同类型的联接谓词之间的区别,也没有提供一个比较它们将如何操作的框架。
没有什么可以代替理解逻辑处理,而且相对容易理解。
- 想象一个交叉联接。
- 对来自步骤1的所有行评估
on
子句,保留谓词为true
的行。 - (仅用于外部联接)在步骤2中添加任何丢失的外部行。
(注:在实践中,查询优化器可能会找到比上述纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)
我将从一个动画版本的全外部联接开始。接下来有进一步的解释。
解释
源表
首先从一个CROSS JOIN
(也称为笛卡尔积)开始。这没有ON
子句,只是返回两个表的每一行的所有组合。
SELECT A.Colour, B.Colour FROM A CROSS JOIN B
内连接和外连接有一个“ON”从句谓词。
- 内连接:对交叉连接结果中的所有行计算“ON”从句中的条件。如果结果为真,则返回连接行。否则将其丢弃。
- 左外连接:与内连接相同,然后对左表中未匹配任何内容的任何行,在右表列中输出这些为空值。
- 右外连接:与内连接相同,然后对右表中未匹配任何内容的任何行,在左表列中输出这些为空值。
- 全外连接:与内连接相同,然后像左外连接一样保留左侧未匹配的行,像右外连接一样保留右侧未匹配的行。
一些示例:
- SELECT A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour = B.Colour:这是经典的等值连接。
- SELECT A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour NOT IN('Green','Blue'):内连接条件不一定是相等条件,也不一定引用两个表格(甚至是任何一个)中的列。 对交叉连接返回的每一行计算'A.Colour NOT IN('Green','Blue')'。
SELECT A.Colour, B.Colour FROM A INNER JOIN B ON 1 =1
连接条件对于交叉连接结果中的所有行都评估为真,因此这就像一个交叉连接一样。我不会再重复16行的图片了。
SELECT A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour
外连接逻辑上与内连接相同,只是如果左表中的一行(对于左连接)根本不与右表中的任何行连接,则将其保留在结果中,并为右侧列使用NULL
值。
SELECT A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour IS NULL
这只是将之前的结果限制为仅返回B.Colour IS NULL
的行。在这种特殊情况下,这些将是保留下来的行,因为它们在右表中没有匹配,查询返回单个未匹配在B
表中的红色行。这被称为反半连接。
重要的是为IS NULL
测试选择一个不可空的列,或者确保连接条件排除任何NULL
值,以使此模式正常工作并避免仅将具有在该列中具有NULL
值的行带回,而不是未匹配的行。
SELECT A.Colour, B.Colour FROM A RIGHT OUTER JOIN B ON A.Colour = B.Colour
右外连接的操作方式与左外连接类似,只是它们保留右表中不匹配的行并对左侧列进行空值扩展。
SELECT A.Colour, B.Colour FROM A FULL OUTER JOIN B ON A.Colour = B.Colour
全外连接将左外连接和右外连接的行为结合起来,保留左表和右表中所有未匹配行。
SELECT A.Colour, B.Colour FROM A FULL OUTER JOIN B ON 1 = 0
交叉连接中没有行符合1=0
谓词。按照正常的外连接规则,保留来自两边的所有行,并在另一侧表的列中使用 NULL。
SELECT COALESCE(A.Colour, B.Colour) AS Colour FROM A FULL OUTER JOIN B ON 1 = 0
稍加修改前面的查询,就可以模拟两个表的UNION ALL
。
SELECT A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour = 'Green'
请注意,WHERE子句(如有)逻辑上在连接后运行。一种常见的错误是执行左外连接,然后在右表上包含带有条件的WHERE子句,这最终会排除不匹配的行。上述查询执行外连接…
…然后运行“Where”子句。NULL= 'Green'
不会返回true,因此由外部连接保留的行最终被丢弃(以及蓝色的行),有效地将连接转换回内部连接。
如果意图是只包含颜色为绿色的B行以及所有A行,不管正确的语法是什么
SELECT A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour AND B.Colour = 'Green'
SQL Fiddle
请查看这些示例,在SQLFiddle.com上实时运行。
假设您在没有重复列的情况下连接,这是非常常见的情况:
例子
假设您有两个带有单个列的表,数据如下:
A B - - 1 3 2 4 3 5 4 6
请注意,(1,2)是A独有的,(3,4)是共有的,(5,6)是B独有的。
内连接
使用任何等效查询的内连接都会给出两个表的交集,即它们共有的两行。
select * from a INNER JOIN b on a.a = b.b; select a.*, b.* from a,b where a.a = b.b; a | b --+-- 3 | 3 4 | 4
左外连接
左外连接将给出A中的所有行以及B中的任何共有行。
select * from a LEFT OUTER JOIN b on a.a = b.b; select a.*, b.* from a,b where a.a = b.b(+); a | b --+----- 1 | null 2 | null 3 | 3 4 | 4
右外连接
右外连接将给出B中的所有行以及A中的任何共有行。
select * from a RIGHT OUTER JOIN b on a.a = b.b; select a.*, b.* from a,b where a.a(+) = b.b; a | b -----+---- 3 | 3 4 | 4 null | 5 null | 6
完全外连接
完全外连接将给出A和B的并集,即A中的所有行和B中的所有行。如果A中的某些内容在B中没有相应的数据,那么B部分为空,反之亦然。
select * from a FULL OUTER JOIN b on a.a = b.b; a | b -----+----- 1 | null 2 | null 3 | 3 4 | 4 null | 6 null | 5