使用 NOT EXISTS 和 NOT IN 删除会产生不同的结果

And*_*rew 4 postgresql

我正在使用较旧的架构,但不明白为什么我的删除操作(清除孤立记录)在某些情况下无法按预期工作。在其他情况下,两个查询都返回相同的结果:-/

例如,我有 3 个模型:房屋、办公室和地址。 house并且office两者都有对 an 的可为空引用address.id,因此address记录可以属于它们中的任何一个,但地址本身并不指示哪个。

-- query 1
DELETE FROM address adr
WHERE
  NOT EXISTS(SELECT * FROM house  H WHERE H.address_id = adr.id) AND
  NOT EXISTS(SELECT * FROM office O WHERE O.address_id = adr.id);

-- query 2 
DELETE FROM address adr
WHERE
  NOT adr.id IN (select address_id from house) AND
  NOT adr.id IN (select address_id from office);
Run Code Online (Sandbox Code Playgroud)

查询 1:删除 3000 条记录(正确)

查询 2:删除 0 条记录

查询#2 的明显问题是什么?当我检查 #1 删除的记录时,它们确实不存在于house或 中office

小智 14

您的address_id列包含空值,因此您被 SQL 的三值逻辑捕获。

https://www.postgresql.org/docs/current/static/functions-subquery.html#functions-subquery-in描述了以下行为IN

请注意,如果左侧表达式产生 null,或者如果没有相等的右侧值且至少有一个右侧行产生 null,则 IN 构造的结果将为 null,而不是 false。这符合 SQL 对空值的布尔组合的正常规则。

当然NOT应用于 null 是 null,不是 true,请参阅https://www.postgresql.org/docs/current/static/functions-logical.html