T-SQL“不在(选择)不起作用(按预期)”

时间:2019-07-17 23:14:38

标签: sql sql-server sql-server-2012

我有一个普通的一对多关系:

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)

我弄错了,还是应该起作用?

2 个答案:

答案 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