112

I'm trying to execute this query:

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

But I get no results. I tested it, and I know that there is something wrong with the syntax. In MySQL such a query works perfectly. I've added a row to be sure that there is one mac which does not exist in the consols table, but still it isn't giving any results.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kskaradzinski
  • 4,954
  • 10
  • 48
  • 70

3 Answers3

222

When using NOT IN you should ensure that none of the values are 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
)
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 4
    Note: the `WHERE mac IS NOT NULL` clause in the subquery is not needed, since `In(...)` always removes NULLs (and duplicates). Because a set cannot contain NULLs – wildplasser Jan 19 '15 at 23:23
  • 9
    @wildplasser I dunno about that. It wasn't working for me, until I added the `IS NOT NULL`. The nested `SELECT` was returning a few `NULLS`, and that was tripping up the `IN(SELECT...)`. – robins35 Apr 06 '17 at 00:22
  • 5
    I would greatly appreciate an explanation as to why the `IS NOT NULL` causes this to work. – mbarkhau Apr 19 '17 at 14:34
  • 12
    It appears that using `NULL` in a `NOT IN` clause doesn't work because a comparison to `NULL` is neither true nor false. http://www.sqlbadpractices.com/using-not-in-operator-with-null-values/ – mbarkhau Apr 19 '17 at 14:53
  • 2
    I'll add my voice to the group that notices that without "is not null" the query returns no rows, but when adding "is not null" I get the desired values. Great answer. – Ray Toal Apr 22 '18 at 03:10
  • 5
    The query will return no rows in absence of the `is not null` if the subquery produces no matching values and at least one `null` value. From [section 9.22](https://www.postgresql.org/docs/current/static/functions-subquery.html#FUNCTIONS-SUBQUERY-NOTIN) of the current (version 10) PostgreSQL manual: "[…] if there are no equal right-hand values and at least one right-hand row yields null, the result of the NOT IN construct will be null, not true." – Christopher Lewis May 31 '18 at 21:08
36

When using NOT IN, you should also consider NOT EXISTS, which handles the null cases silently. See also 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
  );
Gerbrand
  • 1,561
  • 1
  • 12
  • 20
wildplasser
  • 43,142
  • 8
  • 66
  • 109
12

You could also use a LEFT JOIN and IS NULL condition:

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

An index on the "mac" columns might improve performance.

Frank Heikens
  • 117,544
  • 24
  • 142
  • 135