Selecionar linhas que não estão presentes em outra tabela

173

Eu tenho duas tabelas postgresql:

table name     column names
-----------    ------------------------
login_log      ip | etc.
ip_location    ip | location | hostname | etc.

Quero obter todos os endereços IP dos login_logquais não há uma linha ip_location.
Eu tentei essa consulta, mas gera um erro de sintaxe.

SELECT login_log.ip 
FROM login_log 
WHERE NOT EXIST (SELECT ip_location.ip
                 FROM ip_location
                 WHERE login_log.ip = ip_location.ip)
ERROR: syntax error at or near "SELECT"
LINE 3: WHERE NOT EXIST (SELECT ip_location.ip`

Também estou me perguntando se essa consulta (com ajustes para fazê-la funcionar) é a consulta com melhor desempenho para essa finalidade.

stUrb
fonte

Respostas:

387

Existem basicamente 4 técnicas para esta tarefa, todas elas SQL padrão.

NOT EXISTS

Frequentemente, o mais rápido no Postgres.

SELECT ip 
FROM   login_log l 
WHERE  NOT EXISTS (
   SELECT  -- SELECT list mostly irrelevant; can just be empty in Postgres
   FROM   ip_location
   WHERE  ip = l.ip
   );

Considere também:

LEFT JOIN / IS NULL

Às vezes isso é mais rápido. Frequentemente, o mais curto. Freqüentemente resulta no mesmo plano de consulta que NOT EXISTS.

SELECT l.ip 
FROM   login_log l 
LEFT   JOIN ip_location i USING (ip)  -- short for: ON i.ip = l.ip
WHERE  i.ip IS NULL;

EXCEPT

Curto. Não é tão facilmente integrado em consultas mais complexas.

SELECT ip 
FROM   login_log

EXCEPT ALL  -- "ALL" keeps duplicates and makes it faster
SELECT ip
FROM   ip_location;

Observe que ( por documentação ):

duplicatas são eliminadas, a menos que EXCEPT ALLsejam usadas.

Normalmente, você desejará a ALLpalavra - chave. Se você não se importa, use-o ainda porque isso torna a consulta mais rápida .

NOT IN

Só é bom sem NULLvalores ou se você souber lidar NULLadequadamente. Eu não o usaria para esse fim. Além disso, o desempenho pode se deteriorar com tabelas maiores.

SELECT ip 
FROM   login_log
WHERE  ip NOT IN (
   SELECT DISTINCT ip  -- DISTINCT is optional
   FROM   ip_location
   );

NOT INcarrega uma "armadilha" para NULLvalores de ambos os lados:

Pergunta semelhante no dba.SE direcionada ao MySQL:

Erwin Brandstetter
fonte
2
Qual SQL seria executado mais rapidamente, considerando que os volumes de dados são altos nas duas tabelas. (assumindo em bilhões)
Teja
Exceto todo foi o mais rápido para mim
Dan Parker
Tenha cuidado com LEFT JOIN- se houver várias linhas correspondentes na tabela de pesquisa, isso criará uma entrada duplicada na sua consulta principal para cada linha correspondente, o que pode não ser desejado.
Matthias Fripp
@ MatthiasFripp: exceto que isso nunca pode ocorrer com WHERE i.ip IS NULL, o que significa que não há correspondência.
Erwin Brandstetter
@ erwin-brandstetter: Bom ponto. Tropecei pensando na possibilidade de várias correspondências positivas, mas é claro que todas seriam excluídas.
Matthias Fripp
2

A.) O comando NÃO EXISTE, você está perdendo o 'S'.

B.) Em vez disso, use NOT IN

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;
caleb.breckon
fonte
4
NÃO entrar em grandes conjuntos de dados é uma péssima idéia. Muito, muito devagar. É ruim e deve ser evitado.
Grzegorz Grabek
0

SELECT * FROM testcases1 t WHERE NOT EXISTS ( SELECT 1
FROM executions1 i WHERE t.tc_id = i.tc_id and t.pro_id=i.pro_id and pro_id=7 and version_id=5 ) and pro_id=7 ;

Aqui a tabela testcases1 contém todos os dados e a tabela executions1 contém alguns dados entre a tabela testcases1. Estou recuperando apenas os dados que não estão presentes na tabela exections1. (e até eu estou fornecendo algumas condições internas que você também pode fornecer.) especifique a condição que não deve estar presente na recuperação de dados e deve estar entre colchetes.

Deepak N
fonte
0

isso também pode ser tentado ...

SELECT l.ip, tbl2.ip as ip2, tbl2.hostname
FROM   login_log l 
LEFT   JOIN (SELECT ip_location.ip, ip_location.hostname
             FROM ip_location
             WHERE ip_location.ip is null)tbl2
Ahnaf
fonte
2
WHERE ip_location.ip is null- como a WHEREcondição pode ser verdadeira? Além disso, a subconsulta não é correlacionada.
Istiaque Ahmed