SQL左连接WHERE与AND条件差异:为何示例未表现为内连接行为
原理解释
你看到的“左连接加WHERE过滤条件会等价内连接”的说法是有适用前提的:过滤条件没有对左连接生成的右表NULL值做兼容处理。
先明确LEFT JOIN的标准执行逻辑:
- 第一步根据ON子句的匹配规则关联两表:左表所有记录都会被保留,能和右表匹配上的行直接组合;匹配不到右表记录的左表行,右表所有字段会统一填充NULL值,生成临时结果集。
- 第二步如果存在WHERE子句,会对第一步生成的所有临时行逐行做判断,只有满足WHERE条件的行才会进入最终结果。
之前大家说的“加WHERE变内连接”,指的是类似WHERE B.bonus < 1000这种写法:对于没有匹配到Bonus表的员工行,B.bonus是NULL,NULL和任何数值做比较的结果都是UNKNOWN,会直接被WHERE过滤掉,最后只剩两表能匹配上的行,效果和INNER JOIN一致。
而你写的WHERE COALESCE(B.BONUS,0)<=1000用了COALESCE函数,把右表补的NULL值转换成了0,0<=1000判断为真,所以没有匹配到奖金记录的Brad、John两行不会被过滤,自然不会出现等价内连接的效果,返回结果是正确的。
条件写在ON子句的效果
把过滤条件放到ON里通过AND拼接的写法无法得到正确结果,核心原因是ON子句的作用域只在两表匹配阶段,不会过滤左表的原有记录。
对应SQL写法:
SELECT E.NAME, B.BONUS AS BONUS FROM EMPLOYEE AS E LEFT JOIN BONUS AS B ON E.EMPID = B.EMPID AND COALESCE(B.BONUS,0)<=1000
这个语句执行时,只会在匹配右表记录时判断bonus是否满足<=1000:如果右表有记录满足匹配条件就关联,没有满足条件的记录就给右表字段补NULL,左表的员工记录无论如何都会被保留。代入样例数据的话,Thomas(empId=4)对应的Bonus记录bonus是2000,不满足ON里的条件,所以匹配阶段关联失败,最终会返回(Thomas, NULL)这行错误结果——Thomas实际有2000奖金,本应该被过滤掉。
两种写法的核心差异
- WHERE阶段过滤:是在两表关联完成、所有带NULL补全的临时行生成之后做全局过滤,不管是匹配到的行还是补NULL的行,只要不满足条件就会被丢弃。搭配COALESCE处理NULL值后,既可以保留无奖金的员工,也能正确过滤掉奖金超过1000的员工,符合需求。
- ON阶段加条件:仅用来判断右表哪些记录可以和左表匹配,永远不会丢弃左表的记录。哪怕右表记录因为不满足条件没匹配上,左表行还是会保留,只是右表字段显示为NULL,会把奖金超标的员工也错误返回。
内容的提问来源于stack exchange,提问作者Priyansh
相关产品推荐
相关产品推荐

