Como selecionar todos os registros de uma tabela que não existem em outra tabela?

469

tabela1 (identificação, nome)
tabela2 (identificação, nome)

Inquerir:

SELECT name   
FROM table2  
-- that are not in table1 already
z-boss
fonte

Respostas:

843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

Q : O que está acontecendo aqui?

R : Conceitualmente, selecionamos todas as linhas table1e, para cada linha, tentamos encontrar uma linha table2com o mesmo valor para a namecoluna. Se não houver essa linha, deixamos a table2parte do resultado em branco para essa linha. Em seguida, restringimos nossa seleção escolhendo apenas as linhas no resultado em que a linha correspondente não existe. Finalmente, ignoramos todos os campos do nosso resultado, exceto a namecoluna (a que temos certeza de que existe table1).

Embora possa não ser o método mais eficiente possível em todos os casos, ele deve funcionar basicamente em todos os mecanismos de banco de dados que tentam implementar o ANSI 92 SQL

Kris
fonte
16
@ z-chefe: É também o menos performant em SQL Server: explainextended.com/2009/09/15/...
OMG Pôneis
7
@BunkerBoy: Uma junção esquerda permite que as linhas à direita não existam sem que isso afete a inclusão de linhas à esquerda. Uma junção interna requer linhas à esquerda e à direita para estar presente. O que estou fazendo aqui é aplicar alguma lógica para basicamente obter a seleção reversa de uma junção interna.
Kris
2
omg isso ajudou a visualizar com muita facilidade, outros o colocaram de 5 maneiras diferentes, mas isso ajudou. simples: primeiro você obtém a junção esquerda, tudo em A e tudo em B que corresponde a A. Mas, como acontece nos campos de junção esquerda que não se juntam, são nulos. Então você diz, ok, eu só quero que sejam nulos. Dessa forma, agora você tem todas as linhas em A que não coincidem. Em B
Muhammad Umer
7
Deve-se notar que essas soluções (aceitas e votadas) são as únicas, eu acho, que podem ser editadas para um cenário em que mais de um campo entra em jogo. Especificamente, estou retornando o campo 2, o campo 3 da tabela um, onde a combinação do campo 2 do anúncio de campo não está na segunda tabela. À excepção modificando a aderir a esta resposta, não vejo uma maneira de fazê-lo com alguns dos outros "respostas mais eficientes", argumentou para abaixo
TMWP
1
Apenas certifique-se de usar "WHERE t2.name IS NULL" e não "AND t2.name IS NULL" porque "and" não fornecerá resultados corretos. Eu realmente não entendo o porquê, mas é um fato, eu testei.
user890332
236

Você pode fazer

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

ou

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

Veja esta pergunta para três técnicas para realizar isso

froadie
fonte
38
Isso é incrivelmente lento com grandes quantidades de dados.
Lightbulb1
É, na verdade, é muito lento
sirus
Não deveria ser "da tabela1" na subconsulta da consulta não existe.
Hound
Muito confuso com a forma como isso obteve tantos votos positivos. Acho muito difícil pensar em um motivo para usá-lo, quando há uma abordagem para esse problema que é incrivelmente mais rápida, com aproximadamente o mesmo número de pressionamentos de tecla.
searchengine27
Este funcionou para mim .. Obrigado
Thameem 24/09/19
81

Não tenho pontos de representação suficientes para votar na 2ª resposta. Mas eu tenho que discordar dos comentários na resposta superior. A segunda resposta:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

É MUITO mais eficiente na prática. Não sei por que, mas estou com 800k + de registros e a diferença é tremenda com a vantagem dada à 2ª resposta postada acima. Apenas meus $ 0,02

Tan Rezaei
fonte
30
Na consulta NOT IN, a subconsulta é executada apenas uma vez; na consulta EXISTS, a subconsulta é executada para todas as linhas
Carrick
1
você é incrível :) desta forma eu converter minha consulta 25 segundos utilizando esquerda juntar-se a apenas 0,1 seg
Bassem Shahin
3
as respostas não estão em nenhuma ordem específica; portanto, a segunda resposta não significa o que você pensou que isso significava.
38

Isso é pura teoria dos conjuntos que você pode obter com a minusoperação.

select id, name from table1
minus
select id, name from table2
Inverno
fonte
Você acha que isso é muito eficiente do que a esquerda?
UHS
Deveria ser. O comando menos foi projetado para esta situação exata. Obviamente, a única maneira de julgar por um determinado conjunto de dados é tentar dos dois lados e ver qual é o mais rápido.
Inverno
9
No T-SQL, o operador set é "exceto". Isso é muito conveniente para mim e não causou desaceleração.
2
No SQLite, o operador "menos" também é "exceto".
lifjoy
O MySQL não suporta o operador MINUS.
Muhammad Azeem
16

Cuidado com as armadilhas. Se o campo Nameem Table1conter nulos você está em surpresas. Melhor é:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)
user4872693
fonte
1
COALESCE> ISNULL (ISNULL é uma adição T-SQL inútil para a linguagem que não faz nada novo ou melhor do que COALESCE)
Kris
14

Aqui está o que funcionou melhor para mim.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Isso foi duas vezes mais rápido que qualquer outro método que tentei.

Prumo
fonte
Obrigado, isso funciona bem com grande quantidade de dados também! Mas estou me perguntando sobre o termo 'Exceto'.
PatsonLeaner
7

Esse trabalho afiado para mim

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL
David Fawzy
fonte
1

Consulte a consulta:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Conceitualmente, seria: Buscando os registros correspondentes na subconsulta e, em seguida, na consulta principal, buscando os registros que não estão na subconsulta.

jawahar
fonte
0

Vou repostar (já que ainda não sou legal o suficiente para comentar) na resposta correta ... caso alguém ache que seja necessário explicar melhor.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

E eu vi a sintaxe do FROM precisando de vírgulas entre os nomes das tabelas no mySQL, mas no sqlLite parecia preferir o espaço.

O ponto principal é que quando você usa nomes de variáveis ​​incorretos, isso deixa perguntas. Minhas variáveis ​​devem fazer mais sentido. E alguém deve explicar por que precisamos de uma vírgula ou não.

Adrian Roth
fonte
0

Se você deseja selecionar um usuário específico

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

A tent_npké a chave primária de um usuário

Fragmantedbin
fonte