Mysql: sélectionnez les lignes d'une table qui ne sont pas dans une autre

118

Comment sélectionner toutes les lignes d'une table qui n'apparaissent pas sur une autre?

Tableau 1:

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

Tableau 2:

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

Exemple de sortie pour les lignes de Table1 qui ne sont pas dans Table2:

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

Peut-être que quelque chose comme ça devrait fonctionner:

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

Réponses:

96

Si vous avez 300 colonnes comme vous l'avez mentionné dans un autre commentaire, et que vous souhaitez comparer sur toutes les colonnes (en supposant que les colonnes ont toutes le même nom), vous pouvez utiliser a NATURAL LEFT JOINpour joindre implicitement tous les noms de colonne correspondants entre les deux tables afin que vous pas besoin de taper fastidieusement toutes les conditions de jointure manuellement:

SELECT            a.*
FROM              tbl_1 a
NATURAL LEFT JOIN tbl_2 b
WHERE             b.FirstName IS NULL
Zane Bien
la source
Notez que cela ne fonctionne comme prévu que lorsqu'aucune des colonnes n'a de valeurs NULL. Dans MySQL NULL! = NULL donc chaque ligne qui a une valeur NULL sera retournée même s'il y a une ligne en double dans la deuxième table.
Kyle Kochis
84
Si vous avez 300 colonnes, vous devez repenser votre base de données.
Iharob Al Asimi
hé cela fonctionne pour moi aussi, merci! mais serait-ce un problème si les lignes sont> 300 comme vous l'avez mentionné ci-dessus?
thekucays
Je suis toujours confus au sujet de la requête btw.. et si je change "où b.FirstName est nul" en "où b.LastName est nul" par exemple? quelle est la différence? Je suis désolé d'avoir posé cette question, je suis encore nouveau sur sql: D
thekucays
184

Vous devez effectuer la sous-sélection en fonction d'un nom de colonne, pas *.

Par exemple, si vous aviez un idchamp commun aux deux tables, vous pourriez faire:

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

Reportez-vous à la syntaxe de la sous-requête MySQL pour plus d'exemples.

Stennie
la source
1
Merci pour la clarification! mais je n'ai vraiment pas besoin de baser la sélection de lignes sur un champ, car je suis intéressé par toute variation de n'importe quel champ de la ligne ...
S'il n'y a que quelques colonnes à comparer, vous pouvez effectuer une jointure selon l'exemple de @ Steve. Si vous demandez en fait une comparaison générale des données dans deux tables avec de nombreuses colonnes, vous voudrez probablement chercher un outil de comparaison MySQL .
Stennie
2
Notez que cela renverra toujours un ensemble vide si la colonne que vous regardez dans Table2 contient des valeurs nulles. Ce n'est pas un problème si vous le faites en fonction de la clé primaire, mais pertinent pour les personnes qui essaient d'utiliser cette requête dans d'autres contextes.
Mark Amery
4
Mais que faire si nous parlons de big data? Et Table2 contient 100 millions de lignes, par exemple?
frops
Réponse intelligente et intelligente. Merci mate
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 va vous aider...

Ruzbeh Irani
la source
2
Bonne réponse, économique pour les grands ensembles de données, merci.
ekerner
Fort. Meilleure réponse pour les grands ensembles de données
Ian Chadwick
35

Une jointure gauche standard pourrait résoudre le problème et, si les champs de jointure sont indexés,
devrait également être plus rapide

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
la source
d'accord, je suppose que ça doit être ça, btw pourquoi la WHERE t2.Birthdate Is Nullplace de AND t1.Birthdate = t2.Birthdate?
Parce que si vous ajoutez cela, alors chaque ligne sera renvoyée, vous dites que dans la sortie ne devrait apparaître que les lignes non dans le deuxième tableau
Steve
1
C'est une réponse formidable, car elle ne nécessite pas de retourner toutes les lignes de Table2!
dotancohen
Je suis d'accord, excellente réponse. J'ai une table man-many entre 4 tables, mettre le AND dans la jointure intérieure va certainement être plus économique.
DR.
6

Essayer:

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

Essayez cette simple requête. Cela fonctionne parfaitement.

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

Cela a fonctionné pour moi dans Oracle:

SELECT a.* 
    FROM tbl1 a 
MINUS 
SELECT b.* 
    FROM tbl2 b;
Gennady Sorochan
la source
La question concernait MySQL.
jelder le
-6
SELECT a.* FROM 
FROM tbl_1 a
MINUS
SELECT b.* FROM 
FROM tbl_2 b
Ingrid R. Forsale
la source