左连接包含where子句INSIDE join

时间:2016-07-07 06:28:28

标签: sql-server

假设我们有以下表结构:

DECLARE @Person TABLE
(
    PersonId INT,
    Name VARCHAR(50)
)

DECLARE @Address TABLE
(
    AddressId INT IDENTITY(1,1),
    PersonId INT
)

我们插入两个人的记录:

INSERT INTO @Person (PersonId, Name) VALUES (1, 'John Doe')
INSERT INTO @Person (PersonId, Name) VALUES (2, 'Jane Doe')

但我们只插入John

的地址记录
INSERT INTO @Address (PersonId) VALUES (1)

如果我执行以下查询,我会得到不同的结果

SELECT * 
FROM @Person p
 LEFT JOIN @Address a
    ON p.PersonId = a.PersonId AND a.PersonId IS NULL
 PersonId | Name     | AddressId | PersonId
 1        | John Doe | NULL      | NULL
 2        | Jane Doe | NULL      | NULL

VS

SELECT * 
FROM @Person p
 LEFT JOIN @Address a
    ON p.PersonId = a.PersonId
WHERE a.PersonId IS NULL
 PersonId | Name     | AddressId | PersonId
 2        | Jane Doe | NULL      | NULL

为什么查询会返回不同的结果?

4 个答案:

答案 0 :(得分:2)

第一个查询不符合您的任何条件。因此,它显示@Person表(典型Left join)的所有结果。在第二个查询中,where子句应用于join之后。因此它显示了正确的结果。

答案 1 :(得分:1)

首先:

Person获取所有记录(两个)并加入来自0的{​​{1}}个记录,因为没有任何地址有Address。之后,不会应用其他过滤器。你会看到来自PersonID = NULL

的两条记录

第二

Person获取所有记录(两个),其中一个记录加入Person Address。之后,我们应用了ID = 1过滤器,其中一个已加入WHERE的记录消失了。

答案 2 :(得分:0)

ON子句定义从两个表中显示的所有匹配行。 WHERE子句实际上过滤了行。

在第一个查询中,它返回2行,因为LEFT JOIN返回左表中的所有行,而不管右表中的匹配。

第二个查询返回1行,因为对于PersonId = 1,@ Address表包含匹配的记录,因此a.PersonId为NOT NULL。

答案 3 :(得分:0)

养成从Where条件读取SQL查询的习惯,然后查看joins,这将使您更清楚地了解/了解正在发生或将要返回的内容。

在这种情况下,您说WHERE a.PersonId IS NULL必须发生Select部分,并且必须Join使用以下join条件。

这就是您的计算机正在读取您的查询的结果,因此会产生不同的结果集。

然后相反,在没有where子句的情况下,左表(p)上的结果不必存在于(a)上,但同时(a)上的结果必须为null但他们可能已经不存在了。在这一点上,你的SQL将会被混淆。