PostgreSQL'NOT IN'和子查询


89

我正在尝试执行此查询:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (select consols.mac from consols)

但是我没有结果。我测试了一下,而且我知道语法有问题。在MySQL中,这样的查询可以完美地工作。我添加了一行以确保表mac中不存在该行consols,但仍未给出任何结果。


4
consols.macNULL还是NOT NULL
Mark Byers

Answers:


166

使用NOT IN时,应确保所有值都不为NULL:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (
    SELECT mac
    FROM consols
    WHERE mac IS NOT NULL -- add this
)

4
注意:WHERE mac IS NOT NULL子查询中的子句是不需要的,因为它In(...)总是删除NULL(和重复项)。因为集合不能包含NULL
wildplasser

7
@wildplasser我不知道这一点。在我添加之前,它对我没有用IS NOT NULL。巢SELECT归来了一些NULLS,那绊倒了IN(SELECT...)
robins35'4

2
我将不胜感激地解释为什么其IS NOT NULL起作用的原因。
mbarkhau

7
似乎NULLNOT IN子句中使用不起作用,因为与的比较NULL既不正确也不错误。sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau

2
is not null如果子查询没有匹配值且至少产生一个null值,则查询将不返回不缺少的行。从第9.22节开始当前(版本10)PostgreSQL手册的:“ […]如果没有相等的右手值并且至少一个右手行产生null,则NOT IN构造的结果将为null,不是true 。”
克里斯托弗·刘易斯

29

使用NOT IN时,您还应该考虑NOT EXISTS,它可以静默处理null情况。另见PostgreSQL Wiki

SELECT mac, creation_date 
FROM logs lo
WHERE logs_type_id=11
AND NOT EXISTS (
  SELECT *
  FROM consols nx
  WHERE nx.mac = lo.mac
  );

3
另请注意,使用NOT EXISTSvs时会造成巨大的性能损失... NOT IN
IcanDivideBy0

1
@ IcanDivideBy0在大多数情况下,它们生成相同的查询计划。你测试过了吗?
wildplasser '16

1
在子查询的情况下,使用NOT IN代替NOT EXISTS也可以提高性能。参见wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Gerbrand

8

您还可以使用LEFT JOIN和IS NULL条件:

SELECT 
  mac, 
  creation_date 
FROM 
  logs
    LEFT JOIN consols ON logs.mac = consols.mac
WHERE 
  logs_type_id=11
AND
  consols.mac IS NULL;

“ mac”列上的索引可能会提高性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.