PostgreSQL 'NOT IN' e subconsulta


91

Estou tentando executar esta consulta:

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

Mas não consigo resultados. Eu testei e sei que há algo errado com a sintaxe. No MySQL, essa consulta funciona perfeitamente. Eu adicionei uma linha para ter certeza de que há uma macque não existe na consolstabela, mas ainda não está dando resultados.


4
É a consols.maccoluna NULLou NOT NULL?
Mark Byers

Respostas:


169

Ao usar NOT IN, você deve garantir que nenhum dos valores seja 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
Nota: a WHERE mac IS NOT NULLcláusula na subconsulta não é necessária, pois In(...)sempre remove NULLs (e duplicatas). Porque um conjunto não pode conter NULLs
wildplasser

7
@wildplasser Não sei sobre isso. Não estava funcionando para mim, até eu adicionar o IS NOT NULL. O aninhado SELECTestava retornando alguns NULLS, e isso estava atrapalhando o IN(SELECT...).
robins35

2
Eu apreciaria muito uma explicação de por que as IS NOT NULLcausas disso funcionar.
mbarkhau

7
Parece que usar NULLem uma NOT INcláusula não funciona porque uma comparação com NULLnão é verdadeira nem falsa. sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau

2
A consulta não retornará nenhuma linha na ausência de is not nullse a subconsulta não produzir valores correspondentes e pelo menos um nullvalor. Da seção 9.22 do manual atual do PostgreSQL (versão 10): "[...] se não houver valores iguais à direita e pelo menos uma linha à direita resultar em nulo, o resultado da construção NOT IN será nulo, não verdadeiro . "
Christopher Lewis

29

Ao usar NOT IN, você também deve considerar NOT EXISTS, que trata os casos nulos silenciosamente. Veja também 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
Observe também uma grande perda de desempenho ao usar NOT EXISTSvs... NOT IN
IcanDivideBy0

1
@ IcanDivideBy0 Na maioria dos casos, eles geram o mesmo plano de consulta. Você já testou?
wildplasser

1
Também há um ganho de desempenho ao usar NOT IN em vez de NOT EXISTS, no caso de subconsultas. Consulte wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Gerbrand

8

Você também pode usar uma condição LEFT JOIN e 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;

Um índice nas colunas "mac" pode melhorar o desempenho.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.