SQL Server:左连接导致结果行数少于左表

20

我正在使用SQL Server(我相信它是2005版本)。

我有一个名为TableA的表,它有2列和439行(每一行都是独特的)。

+----------+
|ID | Name |
+----------+

我有一个名为TableB的表格,它有35列和数十万行数据(每一行也都是唯一的)。

+------------------------------------------------------------------------------+
|Date | ID | Name | Blah1 | Blah2 | ... | Hour1 | Hour2 | Hour3 | ... | Hour24 |
+------------------------------------------------------------------------------+
每一行在TableB中都有每小时的观测数据以及其他的信息。现在为了测试目的,我只对今天的日期感兴趣,即2013年4月19日。
如果我执行以下操作:
Select count(*) 
from TableB 
where Date = '4/19/2013 12:00:00 AM'

我得到了10526,这个数字是正确的,因为每天都有10526个不同的位置提供每小时的观测数据。

我想要对TableA和TableB进行左连接on a.id = b.id,这应该会产生一个有439行的结果。

不幸的是,结果只有246行。这怎么可能呢?难道不是LEFT JOIN应该返回TableA中的所有行,无论是否在TableB中有匹配的行吗?

*编辑*

我使用的完整查询如下:

select * 
from TableA as a
left join TableB as b on a.id = b.id 
where RealDate = '4/20/2013 12:00:00 AM'

3
你能展示你使用的完整查询吗? - PSR
@PSR - 我已经编辑了我的原始帖子,包括使用的原始查询。 - codingknob
1
重新表述@LoztInSpace宝贵的评论:在连接之前,对选择表添加约束(使用WHERE)。否则,这些约束将作用于连接的结果输出(并且可能会减少行数甚至少于原始表)。 - Kaya Toast
2个回答

37

尝试以下方法:

select * from TableA as a
left join (SELECT * from TableB where RealDate = '4/20/2013 12:00:00 AM') as b
on a.id = b.id 

或者这样:

select * from TableA as a
left join TableB as b on (a.id = b.id AND RealDate = '4/20/2013 12:00:00 AM')

做到了。谢谢。我是SQL的新手,所以不知道在这种情况下where子句的放置会有如此大的差异。不过我很好奇我的原始查询实际上是在做什么。如果它没有意义,那么246行的结果是什么? - codingknob
2
所以,你的查询首先执行了左连接,然后在此基础上通过where子句过滤结果。希望这有意义。如果不理解,我可以进一步解释。 - faisal
发生的情况是,我的原始查询仅返回a.ID = b.ID的行,这不符合左连接的哲学。这很奇怪。但我会接受它并继续前进,因为您的解决方案是正确的,并解决了我的问题。谢谢。感激不尽。 - codingknob
13
这不奇怪 - 这就是它的工作方式。在B.ID没有匹配项的情况下,它会正确地为B引入一个全NULL行。然后您检查B.RealDate ='4/20/2013',但这一条件未能满足。我猜你想查询的是select * from TableA as a left join TableB as b on (a.id = b.id **AND RealDate = '4/20/2013 12:00:00 AM'**) - LoztInSpace
@LoztInSpace - 啊,是的,你说得完全正确。现在我明白了。谢谢。Faisal提供的查询解决了问题,这也是你所指示的。谢谢。 - codingknob
需要注意的是,第二个查询比第一个查询执行速度要快得多。 - Constantino

0
看到其他答案,我也想发表一下我的意见(根据问题中的用例:我们想要应用ReadDateFilter然后进行连接):
我们应该尝试遵循以下步骤(让我们称之为查询1): select * from TableA as a left join (SELECT * from TableB where RealDate = '4/20/2013 12:00:00 AM') as b on a.id = b.id 如果RealDate属于Table A: (select * from TableA where RealDate = '4/20/2013 12:00:00 AM') as a left join (SELECT * from TableB ) as b on a.id = b.id 即先应用过滤器再进行连接。
而不是以下方式(查询2): select * from TableA as a left join TableB as b on (a.id = b.id AND RealDate = '4/20/2013 12:00:00 AM') 原因:如果RealDate属于TableA,则查询2实际上会选择TableA中的所有行,这是错误的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接