LeetCode无订单客户问题:左连接中比较运算符失效原因
为什么不同写法结果差异这么大?
1. LEFT JOIN + WHERE o.customerid IS NULL 能正确工作的原因
用LEFT JOIN关联Customers(c)和Orders(o)时,Customers的所有记录都会被保留:
- 下过单的客户,会和Orders里对应记录匹配,o.customerid就是该客户的id;
- 从未下单的客户,Orders侧没有匹配记录,所有Orders字段都会是
NULL。
这时候用WHERE o.customerid IS NULL,就能精准筛选出无匹配订单的客户——只有从未下单的客户,对应的o.customerid才会是NULL,逻辑直接准确。
2. WHERE c.id <> o.customerid 为什么不行?
SQL里的NULL是特殊值,任何和NULL的比较运算结果都是UNKNOWN,数据库会把UNKNOWN当作False处理:
- 从未下单的客户:o.customerid是
NULL,c.id <> o.customerid等价于c.id <> NULL,结果是UNKNOWN,会被WHERE条件过滤; - 下过单的客户:
c.id = o.customerid,所以c.id <> o.customerid是False,同样被过滤。
最终这个条件根本选不到任何记录,自然得不到正确结果。
3. 直接用 NOT IN(o.customerid) 为什么不行?
这里的o.customerid是单一行的字段,不是完整集合。这种写法本质是把Customers和Orders做笛卡尔积(所有客户和所有订单配对),逐行检查:
- 下过单的客户:只要有一个订单的customerid等于他的id,配对到该订单时
NOT IN(o.customerid)不成立,但配对到其他订单时可能成立,会导致该客户被错误返回; - 从未下单的客户:和所有订单配对时
NOT IN(o.customerid)都成立,会被重复返回多次。
结果要么包含错误客户,要么数据重复,完全不符合需求。
4. NOT IN 搭配子查询为什么可行?
写成NOT IN(SELECT o.customerid FROM Orders o)时,子查询会先执行,把所有下过单的客户id收集成一个完整集合。然后逐个检查Customers里的客户id:
- 从未下单的客户:id不在集合里,
NOT IN条件成立,会被选中; - 下过单的客户:id在集合里,
NOT IN条件不成立,会被排除。
这种写法是拿客户id和整个“已下单客户id集合”做比较,逻辑精准,所以能得到正确结果。
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

