Mysql: Selecione linhas de uma tabela que não estão em outra

118

Como selecionar todas as linhas de uma tabela que não aparecem na outra?

Tabela 1:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Mesa 2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
+-----------+----------+------------+

Exemplo de saída para linhas na Tabela 1 que não estão na Tabela 2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Talvez algo assim deva funcionar:

SELECT * FROM Table1 WHERE * NOT IN (SELECT * FROM Table2)
Christopher Rapcewicz
fonte

Respostas:

96

Se você tiver 300 colunas como mencionou em outro comentário, e quiser comparar em todas as colunas (assumindo que todas as colunas têm o mesmo nome), você pode usar um NATURAL LEFT JOINpara unir implicitamente em todos os nomes de coluna correspondentes entre as duas tabelas para que você não precisa digitar tediosamente todas as condições de junção manualmente:

SELECT            a.*
FROM              tbl_1 a
NATURAL LEFT JOIN tbl_2 b
WHERE             b.FirstName IS NULL
Zane Bien
fonte
Observe que isso só funciona conforme o esperado quando nenhuma das colunas tem valores NULL. No MySQL NULL! = NULL então cada linha que tem um valor NULL será retornada mesmo se houver uma linha duplicada na segunda tabela.
Kyle Kochis
84
Se você tiver 300 colunas, deverá redesenhar seu banco de dados.
Iharob Al Asimi
ei, isso funciona para mim também, obrigado! mas isso seria um problema se as linhas fossem> 300 como você mencionou acima?
thekucays
Ainda estou confuso sobre a consulta btw ... e se eu alterar "onde b.FirstName é nulo" para "onde b.LastName é nulo", por exemplo? qual é a diferença? desculpe por perguntar isso, ainda sou novo no sql: D
thekucays
184

Você precisa fazer a subseleção com base no nome de uma coluna, não *.

Por exemplo, se você tivesse um idcampo comum a ambas as tabelas, poderia fazer:

SELECT * FROM Table1 WHERE id NOT IN (SELECT id FROM Table2)

Consulte a sintaxe da subconsulta do MySQL para mais exemplos.

Stennie
fonte
1
obrigado pelo esclarecimento! mas eu realmente não preciso basear a seleção de linhas em nenhum campo, porque estou interessado em qualquer variação de qualquer campo na linha ...
Se houver apenas algumas colunas para comparar, você pode fazer uma junção conforme o exemplo de @S Steve. Se você está realmente pedindo uma comparação geral de dados em duas tabelas com muitas colunas, provavelmente deseja procurar uma ferramenta diff do MySQL .
Stennie 01 de
2
Observe que isso sempre retornará um conjunto vazio se a coluna que você está vendo na Tabela 2 contiver nulos. Não é um problema se você está fazendo isso com base na chave primária, mas é relevante para as pessoas que estão tentando usar essa consulta em outros contextos.
Mark Amery
4
Mas e se estivermos falando de big data? E a Tabela 2 contém 100 milhões de linhas, por exemplo?
frops
Resposta inteligente e inteligente. Obrigada colega
Anjana Silva
44
SELECT *
FROM Table1 AS a
WHERE NOT EXISTS (
  SELECT *
  FROM Table2 AS b 
  WHERE a.FirstName=b.FirstName AND a.LastName=b.Last_Name
)

EXISTS Ajudará você...

Ruzbeh Irani
fonte
2
Boa resposta, econômica para grandes conjuntos de dados, obrigado.
ekerner
Forte. Melhor resposta para grandes conjuntos de dados
Ian Chadwick
35

Um LEFT JOIN padrão pode resolver o problema e, se os campos na junção forem indexados,
também deve ser mais rápido

SELECT *
FROM Table1 as t1 LEFT JOIN Table2 as t2 
ON t1.FirstName = t2.FirstName AND t1.LastName=t2.LastName
WHERE t2.BirthDate Is Null
Steve
fonte
Tudo bem, acho que deve ser isso, btw por que o em WHERE t2.Birthdate Is Nullvez de AND t1.Birthdate = t2.Birthdate?
Porque se você adicionar isso, todas as linhas serão retornadas, você diz que na saída devem aparecer apenas as linhas que não estão na segunda tabela
Steve
1
Esta é uma resposta excelente, pois não exige o retorno de todas as linhas de Table2!
dotancohen
Eu concordo, ótima resposta. Eu tenho uma tabela man-many entre 4 tabelas, colocar AND na junção interna definitivamente será mais econômico.
DR.
6

Experimentar:

SELECT * FROM table1
    LEFT OUTER JOIN table2
    ON table1.FirstName = table2.FirstName and table1.LastName=table2.LastName
    WHERE table2.BirthDate IS NULL
Sachin Pundir
fonte
4

Experimente esta consulta simples. Funciona perfeitamente.

select * from Table1 where (FirstName,LastName,BirthDate) not in (select * from Table2);
Vijesh
fonte
-3

Isso funcionou para mim no Oracle:

SELECT a.* 
    FROM tbl1 a 
MINUS 
SELECT b.* 
    FROM tbl2 b;
Gennady Sorochan
fonte
A pergunta era sobre o MySQL.
jelder
-6
SELECT a.* FROM 
FROM tbl_1 a
MINUS
SELECT b.* FROM 
FROM tbl_2 b
Ingrid R. Forsale
fonte