这是我的数据
CREATE TABLE TempA (
ID INT IDENTITY(1,1),
Msg VARCHAR(20)
)
INSERT INTO TempA (Msg) values ( 'a')
INSERT INTO TempA (Msg) values ( 'b')
INSERT INTO TempA (Msg) values ( 'c')
CREATE TABLE TempB (
ID INT IDENTITY(1,1),
Msg VARCHAR(20)
)
所以TempB是空的。现在我运行以下查询
select a.*
from TempA a
left JOIN TempA B on a.id = b.id
它按预期从TempA返回3行,到目前为止还不错。让我们在上面的查询中添加一个过滤器
select a.*
from TempA a
left JOIN TempA B on a.id = b.id
where b.msg = 'aa'
它不向我返回任何行。我认为,因为它是一个左连接,我仍然应该从TempA表获得3行。我错了吗?
答案 0 :(得分:4)
您正在通过在b.msg
子句使用中包含where
过滤器将左连接转换为内连接。
select a.* from TempA a left JOIN TempB B on a.id = b.id and b.msg = 'aa'
(从概念上讲)加入谓词发生时,来自A的非加入行会重新加入,NULL
的值为b.msg
,然后您再次使用过滤器排除这些行!
您可能想要查看Itzik Ben Gan的Logical Query Processing Poster
答案 1 :(得分:4)
这是正在发生的事情;
你有两张桌子。
TempA ID Msg
-- ---
1 a
2 b
3 c
TempB ID Msg
-- ---
现在,当您进行连接时,初始结果如下所示:
Result a.ID a.Msg b.ID b.Msg
---- ----- ---- -----
1 a NULL NULL
2 b NULL NULL
3 c NULL NULL
当您使用WHERE
子句过滤该查询时,您将过滤掉b.Msg
'aa'
b.Msg
的任何内容。这会过滤掉所有记录,因为所有记录都有NULL
Result a.ID a.Msg b.ID b.Msg
---- ----- ---- -----
。离开你:
TempA
然后,您只选择Result a.ID a.Msg
---- -----
中的列,这是最终结果:
{{1}}
答案 2 :(得分:2)
使用OUTER JOIN时,WHERE
子句中提供的条件在 JOIN后应用 。因为没有b.msg ='aa'的行,所以不会返回任何行。
在ON
子句中指定条件后,条件将在 JOIN之前应用,因此对b
的引用只会是影响。在此示例中,b
引用将返回NULL,而a
引用不受影响。
答案 3 :(得分:1)
我更喜欢马丁的解决方案,但另一个选择是
select a.*
from
TempA a
left JOIN TempB B on a.id = b.id
where b.msg = 'aa' or b.msg is null
答案 4 :(得分:0)
这取决于你如何进行过滤 几个月前我回答了类似的问题。看看我关于左连接的解释:
What is the difference in these two queries as getting two different result set?