2016-07-07 77 views
1

假设我们有如下表结构:左加入含where子句INSIDE加入

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 

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

+1

它变成了一个内部联接:http://stackoverflow.com/questions/3256304/left-join-turns-into-inner-join –

+0

因为PersonID上的'LEFT JOIN'确实产生了一个匹配,并且PersonID不为NULL那一排。 –

回答

2

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

1

第一:

得到所有记录Person(二),从Address加入0记录,COS没有地址的有PersonID = NULL。之后,没有应用其他过滤器。你从Person

其次看到两个记录:

得到的所有记录(二)从Person,其中一个连接到AddressID = 1。之后,您的WHERE筛选器已应用,并且加入ID = 1的记录之一消失。

0

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

在第一个查询中,它返回2行,因为LEFT JOIN返回左表中的所有行,与来自右表的匹配无关。

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

0

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

在这种情况下,你说WHERE a.PersonId IS NULLSelect部分必须发生,它必须Join使用以下join条件。

这就是您的查询正在被您的机器读取的方式,因此有不同的结果集。

然后相反,在没有where子句的情况下,左表(p)上的结果不必存在于(a)上,但同时(a)上的结果必须是为空但已经可能不存在。在这一点上,你的SQL会感到困惑。