我有一个普通的一对多关系:
customer.id = order.customerid
我想找到没有关联订单的客户。
我尝试过:
-- one record
select * from customers where id = 123
-- no records
select * from orders where customerid = 123
-- NO RECORDS
select *
from customers
where id not in (select customerid from orders)
-- many records, as expected.
select *
from customers
where not exist (select customerid from orders
where customers.customerid = customer.id)
我弄错了,还是应该起作用?
答案 0 :(得分:2)
我通常通过左联接来执行此操作,该联接查找联接失败时创建的空值:
SELECT c.*
FROM
customers c
LEFT JOIN orders o
ON c.id = o.customerid
WHERE
o.customerid IS NULL
左联接将客户表视为“实体”,并在有给定客户ID的订单的情况下将订单连接到该表,而在没有任何匹配订单的情况下将null放置,因此关系的订单方具有“漏洞”在数据中。通过说我们只想看到这些漏洞(通过where子句),我们得到了“没有订单的客户”列表
根据评论,我一直遵循“不要在列表中使用IN的时间超过您要手工编写的列表”的规则,但是越来越多的优化人员正在重写IN,EXISTS和LEFT JOIN WHERE NULL查询以使其起作用完全相同,因为它们都是“ A中的数据,B中没有匹配的数据”的模式
答案 1 :(得分:2)
NOT IN
的值时, NULL
的行为不符合预期。
实际上,如果任何值为NULL
,则根本不会返回任何行。切记:在SQL中,NULL
表示“不确定”值,而不是“缺失值”。因此,如果列表包含任何NULL
值,则它可能等于比较值。
因此,customerid
必须在NULL
表中为orders
。
由于这个原因,我强烈建议您始终对子查询使用NOT EXISTS
而不是NOT IN
。