为什么两个查询不同(左连接...和...而不是使用where子句)

时间:2014-06-18 15:43:25

标签: sql oracle

我想知道为什么以下两个查询产生不同的结果(第一个查询的行数多于第二个)。

SELECT * FROM A
  JOIN ...
  JOIN ...
  JOIN C ON ...
  LEFT JOIN B ON B.id = A.id AND B.otherId = C.otherId

相反:

SELECT * FROM A
  JOIN ...
  JOIN ...
  JOIN C ON ...
  LEFT JOIN B ON B.id = A.id
WHERE B.otherId = C.otherId

请帮我理解。在第二个查询中,左连接只有1个条件,因此它不应包含第一个查询的所有结果以及更多(其他行具有不匹配的otherId)。然后WHERE子句应确保otherId匹配,就像在第一个查询中一样。他们为什么不同?

3 个答案:

答案 0 :(得分:2)

在执行WHERE之前,JOIN首先由查询引擎执行 如果我们稍后要过滤某些行,原因就是为什么要使用昂贵的JOIN。 查询引擎非常擅长优化您编写的查询。

此外,您只会在OUTER JOIN s中看到此效果。在内连接中,WHEREJOIN条件的行为相同。

答案 1 :(得分:1)

第二个查询返回的行数较少,因为您的where子句正在过滤掉记录,这实质上是将查询从左外连接更改为内连接。因此,您需要小心放置过滤器的位置,但如果您要进行内部连接则无关紧要。

答案 2 :(得分:0)

您已收到正确的答案,但请允许我深入研究加入条件和过滤条件之间的区别。使用左连接进行简单查询:

select a.Key, a.NonKey1, b.NonKey2
from a
left join b on b.Key = a.Key;

这会列出表NonKey1中的所有a值以及表NonKey2中具有匹配键值的所有b字段,或NULL没有匹配键值比赛。一个常见的变体是只查看ab中没有匹配项的那些行:

select a.Key, a.NonKey1, b.NonKey2
from a
left join b on b.Key = a.Key
where b.Key is null;

小心!如果您不小心写了where b.Key is not null,那么您刚刚将外部联接更改为常规内部联接。这样做,看看质量保证是否能抓住它。第二个想法,不要。 (此外,在选择列表中使用b.NonKey2是没有意义的,因为它只能是NULL,但暂时让它保留在那里。)连接基于两个表匹配的关键字段。加入完成后,将丢弃所有成功加入的行,并且仅保留没有匹配的结果。这意味着加入条件中的b.Key不能NULL,而过滤条件必须NULL才能添加一行到结果集。好的,这就是我们想要的。但是考虑如果我们将支票移动到加入标准的一部分会发生什么。

select a.Key, a.NonKey1, b.NonKey2
from a
left join b on b.Key = a.Key and b.Key is null;

结果是来自a的所有内容,b完全没有任何内容。可能不是我们想要的。如果你仔细想想,你会发现我们也可以写on 0 = 1并得到相同的结果。我们所做的是从一个上下文中移动一个值,其中NULL表示一件事(成功)到NULL表示完全不同(失败)的上下文。

因此,在人类语言的计算机语言中,要注意上下文。它可以彻底改变你想说的内容。