如果我有一个查询:
SELECT * FROM A
INNER JOIN B ON B.ID = A.ID
INNER JOIN C ON C.ID = B.ID
这会为此查询返回不同的结果吗?
SELECT * FROM A
INNER JOIN B ON B.ID = A.ID
INNER JOIN C ON C.ID = A.ID
在我看来,在第一个查询中我会得到 A、B、C 的交集。在第二个查询中,我将得到 A、B 的交集以及 A、C 的交集。
如果是这种情况,我会在 B、C 之间没有交集的 B/C 列中找到 NULL 值吗?
不,这两个查询是相同的。
既然
A.ID = B.ID
和A.ID = C.ID
,那么根据定义B.ID = C.ID
。对于任何给定的 ID x,如果有一行
A
带有 ID 和一行B
带有 ID,但没有一行C
带有 ID,则来自A
和的B
行将被忽略,因为两个连接都是INNER JOIN
s。当然,同样适用于A-C-B
和B-C-A
。因此,当所有
JOIN
s 都是INNER JOIN
s时,获取给定列的唯一方法NULL
是该列是否NULL
在现有行中 - 您不能NULL
在一个表中填写一行 s 因为没有匹配的行,因为缺少一个INNER JOIN
ed 表中的匹配行意味着其他表中的行无效。换句话说 - 对于 中的给定行
B
,如果 中没有匹配的行,那么使用该行C
的行也没有匹配项。该行(以及与其匹配的任何行)不会被包括在内,因为所有ed 表都必须存在一行。A JOIN B
B
B
A
INNER JOIN
A INNER JOIN B RIGHT OUTER JOIN C
如果查询是or ,您询问是否有任何变化A LEFT OUTER JOIN B INNER JOIN C
。它可以改变。
在正常情况下,将从左到右评估连接(即从第一个列出的连接到最后一个)。
如果出于某种原因您必须修改该行为,您可以通过移动
ON
子句的位置来实现。根据您的 DBMS,您可能还必须添加括号以指示应评估子句的顺序(我尝试了 MS SQL 和 MySQL;MySQL 需要括号才能工作,MS SQL 允许但不需要它们)。我在下面的示例中包含了括号,这些括号不会从左到右求值,以帮助说明这一点。例子:
A INNER JOIN B ON <condition1> RIGHT OUTER JOIN C ON <condition2>
这将首先连接
A
和B
(需要匹配<condition1>
以关联两个表中的行),然后执行右外连接到C
(其中C
满足WHERE
条件的所有行将被返回,并将与A-B
连接中的任何行相关联 where<condition2>
被满足。A INNER JOIN (B RIGHT OUTER JOIN C ON <condition1>) ON <condition2>
另一方面,这将连接 B 和 C(包括来自
C
满足WHERE
子句的所有行,与来自B
满足的任何行相关联<condition1>
。然后,连接的结果与B-C
内部连接A
,与来自的行相关联A
和B-C
基于 的匹配行<condition2>
。请注意,在这里,您将获得 和 的不同结果A.id - B.id
,A.id = C.id
因为所有行都将具有非 NULLC.id
,但B.id
在没有来自 的匹配行的情况下将为 NULLB
。A LEFT JOIN B ON <condition1> INNER JOIN C ON <condition2>
对于
ON
通常位置的子句,这是从左到右求值的。因此,首先我们从 中获取所有行A
,将它们与B
基于 的任何匹配行相关联<condition1>
;然后,我们对A-B
join with的结果进行内部联接C
,仅返回其中一行 from与based on的行A-B
相匹配的行。C
<condition2>
A LEFT JOIN (B INNER JOIN C ON <condition1>) ON <condition2>
在这里,我们再次强制
B-C
首先发生内部连接,因此当来自的行与基于的行B
匹配时,我们会获取行;然后,我们获取内部连接的结果并将其匹配到(返回来自 的所有行,以及来自based 的任何匹配行C
<condition1>
B-C
A
A
B-C
<condition2>
这里有几个 SQLFiddle 链接显示了这些连接的结果,当您在
ON
子句中移动时:一个用于MySQL,一个用于MS SQL Server。注意:我没有说这如何与非 ANSI 连接语法一起工作。如果你不知道我在说什么 - 感谢你的幸运星并继续前进。我不确切知道优先级如何与该语法一起使用。我希望它从左到右(首先提到到最后)遍历表格列表。显然,由于没有
ON
条款,因此没有任何影响。可能有办法强制执行那里的命令(也许又是括号,大概在FROM
子句中?),但我不知道答案。由于大多数人(包括我自己)强烈建议不要尝试对您JOIN
的 s 使用该语法,因此我将简单地使用它来避免问题 :-)。