为什么内部联接会覆盖以前的外部联接?

时间:2019-10-09 12:15:45

标签: sql oracle join

我知道这是一个基本问题,但同样为什么我很难理解这种情况。假设我们有3个表(A,B,C),它们都具有1-1关系。但是表B并不包含表A包含的所有值。因此,它们之间必须保持左连接。那么,为什么下面的代码将所有联接变成一个内部联接,而唯一的内部联接却不仅仅在B和C表之间起作用?你能给我解释一下吗?

SELECT A.*
FROM A
LEFT OUTER JOIN B ON B.ID = A.ID
INNER JOIN C ON C.ID = B.ID

这个问题不是关于外部联接或内部联接可以或不能使用表中的值的问题。关于它们一起使用时,sql引擎如何在它们上工作?也许这里的执行顺序是什么?这就是我试图理解的。谢谢。

4 个答案:

答案 0 :(得分:1)

这里的问题与理解JOIN的处理顺序有关。

首先执行LEFT OUTER JOIN,并将按预期返回A的所有结果,以及B的那些匹配结果(如果连接失败,则返回NULL的值)。

此后,然后针对第一个INNER JOIN的合并结果执行CLEFT OUTER JOIN。由于没有匹配项将BC的不存在的匹配项加入进来,因此将这些结果从结果中排除 ,为您提供缩减的​​结果。

迎合这种情况的典型方法是使用第二个LEFT OUTER JOIN代替INNER JOIN

SELECT *
  FROM A
    LEFT OUTER JOIN B ON B.ID = A.ID
    LEFT OUTER JOIN C ON C.ID = B.ID

这仍将返回A中的所有内容,并且仅返回BC中的匹配记录。

如果打算仅在B中返回 结果,而在C中具有相应的条目,则可以将查询的工作方式修改为类似未测试 SQL:

SELECT *
  FROM A
    LEFT OUTER JOIN (
                    SELECT B.ID
                      FROM B
                       INNER JOIN C ON C.ID = B.ID
                    ) btmp ON btmp.ID = A.ID

这只会返回B中与C 中的行匹配的结果,然后将它们加入A

答案 1 :(得分:1)

A left outer join B意味着从A返回所有内容,即使B中没有匹配的内容,对吗? 因此,您将从A中获得每一行,其中NULL代表B中没有对应关系的行,而值与那些在B中具有匹配项的行对应。

然后将此集合(inner joined)与C相连。这意味着(A left join B) and C之间只有匹配的那些,并且连接条件位于column of B =>上,而实际上有一个匹配的首先显示A的值。其他的是NULL

article是SQL中联接的出色视觉说明。

答案 2 :(得分:1)

简单地说,如果在表B中找不到匹配项,则此:

INNER JOIN C ON C.ID = B.ID

表示:

INNER JOIN C ON C.ID = NULL

连接条件失败。

您可以添加括号以获得预期结果:

SELECT A.*
FROM A
LEFT OUTER JOIN (B INNER JOIN C ON B.ID = C.ID) ON A.ID = B.ID

答案 3 :(得分:0)

比较这两个查询(第一个查询可能看起来不正确,但这是正确的!)

SELECT A.* FROM A 
    LEFT OUTER JOIN B  
        INNER JOIN C ON C.ID = B.ID
    ON B.ID = A.ID

vs

SELECT * FROM A 
    LEFT OUTER JOIN B ON B.ID = A.ID 
    INNER JOIN C ON C.ID = B.ID

在第二个查询中,您询问: 不要将b加入a 并将c与上一步的结果进行内部联接。

最后一个内部联接将忽略所有空记录

但是第一个查询是不同的 问: 将C内部连接到B,然后将结果左连接到A

在这种情况下,来自A的所有与内部联接结果不对应的记录都将包含在结果中。