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)

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

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.


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ê...


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

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

4

Experimente esta consulta simples. Funciona perfeitamente.

select * from Table1 where (FirstName,LastName,BirthDate) not in (select * from Table2);

-3

Isso funcionou para mim no Oracle:

SELECT a.* 
    FROM tbl1 a 
MINUS 
SELECT b.* 
    FROM tbl2 b;

A pergunta era sobre o MySQL.
jelder

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.