10

我一直很难在谷歌上搜索这个答案,但是....有人可以向我解释一下将 JOIN 的 ON 条件与 JOIN 本身放在一起与将 ON 放在所有其他 JOIN 的末尾之间的区别吗? .

这是一个例子http://sqlfiddle.com/#!3/e0a0f/3

CREATE TABLE TableA (Email VARCHAR(100), SomeNameA VARCHAR(100))
CREATE TABLE Tableb (Email VARCHAR(100), SomeNameB VARCHAR(100))
CREATE TABLE Tablec (Email VARCHAR(100), SomeNameC VARCHAR(100))

INSERT INTO TableA SELECT 'joe@test.com', 'JoeA'
INSERT INTO TableA SELECT 'jan@test.com', 'JaneA'
INSERT INTO TableA SELECT 'dave@test.com', 'DaveA'
INSERT INTO TableB SELECT 'joe@test.com', 'JoeB'
INSERT INTO TableB SELECT 'dave@test.com', 'DaveB'
INSERT INTO TableC SELECT 'joe@test.com', 'JoeC'
INSERT INTO TableC SELECT 'dave@test.com', 'DaveC'


SELECT TOP 2 a.*,
             b.*,
             c.*
FROM   TableA a
       LEFT OUTER JOIN TableB b
                    ON a.email = b.email
       INNER JOIN TableC c
                    ON c.Email = b.email;

SELECT TOP 2 a.*,
             b.*,
             c.*
FROM   TableA a
       LEFT OUTER JOIN TableB b
       INNER JOIN TableC c
                    ON c.Email = b.email
                    ON a.email = b.email;

我不明白为什么这两个 SELECT 语句会产生不同的结果。

4

2 回答 2

12

重要的是连接的顺序。将您的表达式视为每个连接都生成临时“虚拟”表。

所以当你写

FROM TableA a 
LEFT OUTER JOIN TableB b ON a.email = b.email
INNER JOIN TableC c ON c.Email = b.email ;

那么顺序如下:

  1. TableA被留下来TableB产生临时关系V1
  2. V1是内联的TableC

当你写的时候:

FROM TableA a 
LEFT OUTER JOIN TableB b 
INNER JOIN TableC c ON c.Email = b.email ON a.email = b.email;

那么顺序如下:

  1. TableB内联TableC产生临时关系V1
  2. TableA左连接到V1

因此结果是不同的。一般建议在这种情况下使用括号来提高查询的可读性:

FROM TableA a 
LEFT OUTER JOIN
  (TableB b INNER JOIN TableC c ON c.Email = b.email)
ON a.email = b.email;
于 2012-08-30T11:09:28.317 回答
4

在您的第二个示例中,该部分ON a.email = b.email属于LEFT JOIN.
如果这样写,则表示如下:

INNER JOIN表 C 与表 B 和LEFT OUTER JOIN结果与表 A。

结果将是 TableA 中的所有行与 TableB 中在 TableC 中也有条目的那些行相连接。

第一个例子的含义如下:

LEFT OUTER JOINTableB 与 TableA 和INNER JOINTableC 与结果。这相当于使用INNER JOINfor TableB。
说明:当您LEFT OUTER JOIN使用 TableA 和 TableB 时,您将从 TableA 中获取所有行,并且对于 TableB 中的匹配行,您也将获得该数据。在您的结果集中,您将拥有带有b.email=的行,NULL现在这将INNER JOIN使用 TableC 进行编辑。只要 TableC 中没有带有email=的条目,NULL您就会得到观察到的结果。

于 2012-08-30T11:03:46.673 回答