为何将WHERE子句条件移至JOIN子句会导致SQL Server查询结果不同?
两个左连接查询结果不同的原因解析
核心差异:过滤条件的位置(ON子句 vs WHERE子句)
这两个查询的本质区别在于ff.sendtime < '2023-01-21'条件的放置位置,直接改变了左连接的执行逻辑和最终统计范围:
- 第一个查询的执行逻辑
select count(*) from ff left join d on ff.ID = d.id where ff.sendtime < '2023-01-21' and d.id is null
- 第一步:执行全量左连接——将
ff表的所有记录(无论sendtime取值)按ID与d表关联,关联失败的记录会保留d表字段为NULL。 - 第二步:执行WHERE过滤——仅保留
ff.sendtime < '2023-01-21'且未匹配到d表的记录。 - 最终统计:ff表中
sendtime早于2023-01-21且在d表无匹配ID的记录数。
- 第二个查询的执行逻辑
select count(*) from ff left join d on ff.sendtime < '2023-01-21' and ff.ID = d.id where d.id is null
- 第一步:执行带条件的左连接——仅当
ff.sendtime < '2023-01-21'且ff.ID = d.id时,才会尝试关联d表;对于ff.sendtime >= '2023-01-21'的记录,因不满足ON子句条件,不会与d表关联,直接保留且d表字段为NULL。 - 第二步:执行WHERE过滤——保留所有
d.id is null的记录,包含两类:- ff表中
sendtime早于2023-01-21但未匹配到d表的记录; - ff表中
sendtime >= 2023-01-21的所有记录(这类记录未参与关联,d.id自然为NULL)。
- ff表中
- 最终统计:ff表中
sendtime >= 2023-01-21的所有记录 +sendtime早于2023-01-21且在d表无匹配ID的记录。
等价写法调整
若要让第二个查询与第一个返回相同结果,需将ff.sendtime < '2023-01-21'移至WHERE子句(即第一个查询的写法),或在ON子句外补充过滤条件:
select count(*) from ff left join d on ff.ID = d.id where ff.sendtime < '2023-01-21' and d.id is null
内容的提问来源于stack exchange,提问作者SnowStorm
相关产品推荐
相关产品推荐

