123

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.

1
  • 4
    Is the consols.mac column NULL or NOT NULL? Commented Dec 11, 2011 at 9:40

3 Answers 3

241

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
)
Sign up to request clarification or add additional context in comments.

6 Comments

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 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...).
I would greatly appreciate an explanation as to why the IS NOT NULL causes this to work.
It appears that using NULL in a NOT IN clause doesn't work because a comparison to NULL is neither true nor false. sqlbadpractices.com/using-not-in-operator-with-null-values
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 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."
|
37

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
  );

5 Comments

Also note a huge performance loss when using NOT EXISTS vs ... NOT IN
@IcanDivideBy0 In most cases they generate the same query plan. Have you tested it?
There's also a performance gain in using NOT IN instead of NOT EXISTS, in case of subqueries. See wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
@Gerbrand your link seems to indicate you gain performance if using EXISTS instead of IN. Contrary to what you said....
Will this method work if the order of mac is different in both tables?
13

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.