Supprimer les lignes sql où les ID ne correspondent pas à une autre table

161

J'essaye de supprimer les entrées orphelines dans une table mysql.

J'ai 2 tables comme celle-ci:

Tableau files:

| id | ....
------------
| 1  | ....
| 2  | ....
| 7  | ....
| 9  | ....

table blob:

| fileid | ....
------------
| 1  | ....
| 2  | ....
| 3  | ....
| 4  | ....
| 4  | ....
| 4  | ....
| 9  | ....

Les colonnes fileidet idpeuvent être utilisées pour joindre les tables ensemble.

Je veux supprimer toutes les lignes de la table blobqui fileidne peuvent pas être trouvées dans la table files.id.

Donc, en utilisant l'exemple ci-dessus, cela supprimerait les lignes: 3 et 4 (s) dans le blobtableau.

Martin
la source
1
Passez à la deuxième réponse si vous utilisez nulls.
Pacerier

Réponses:

328

En utilisant LEFT JOIN / IS NULL:

DELETE b FROM BLOB b 
  LEFT JOIN FILES f ON f.id = b.fileid 
      WHERE f.id IS NULL

Utilisation de NOT EXISTS:

DELETE FROM BLOB 
 WHERE NOT EXISTS(SELECT NULL
                    FROM FILES f
                   WHERE f.id = fileid)

Utilisation de NOT IN:

DELETE FROM BLOB
 WHERE fileid NOT IN (SELECT f.id 
                        FROM FILES f)

avertissement

Dans la mesure du possible, effectuez des SUPPRESSIONS dans une transaction (en supposant qu'il soit pris en charge - IE: Pas sur MyISAM) afin que vous puissiez utiliser la restauration pour annuler les modifications en cas de problèmes.

Poneys OMG
la source
12
lequel est, en général, le plus rapide de ce qui précède?
Hampus Brynolf
2
Pour une raison quelconque, la suppression à l'aide de la jointure gauche ne fonctionnait pas sur MS SQL Server Mgmt Studio (je ne sais pas pourquoi; il s'est simplement plaint de la jointure gauche). Tout le monde sait pourquoi? Cela a fonctionné en utilisant NOT EXISTS cependant :)
Anna
5
Pour info, voici une discussion utile sur l'efficacité relative de ces trois méthodes: expliquezextended.com/2009/09/18/...
moustachio
2
@Pacerier - "faux" est un peu fort. Pour que les gens comprennent, les réponses font le travail si fileidest non annulable . De plus, la troisième solution ( NOT IN) ne nécessite que f.idpar non nullable. Il s'agit probablement d'une clé primaire, ce serait donc le cas.
ToolmakerSteve
2
Pour les personnes essayant ceci avec SQLite: voir cette réponse
bunkerdive
26
DELETE FROM blob 
WHERE fileid NOT IN 
       (SELECT id 
        FROM files 
        WHERE id is NOT NULL/*This line is unlikely to be needed 
                               but using NOT IN...*/
      )
Martin Smith
la source
Que signifie "/ * Cette ligne n'est probablement pas nécessaire, mais l'utilisation de NOT IN ... * /" est censée signifier?
Pacerier
1
@Pacerier - NOT IN (NULL)renvoie un jeu de résultats vide, les NULL doivent donc être exclus. Mais une idcolonne ne sera probablement pas annulable de toute façon, donc "peu probable d'être nécessaire"
Martin Smith
Wow bonne prise. Donc la réponse des omgponies est fausse! not in(null)est assez logique, pourquoi ça ne marche pas? Quelle est la raison derrière cela?
Pacerier
1
@bunkerdive Utilisez ensuite trois noms d'objet qui incluent le nom de la base de données.
Martin Smith
18
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
George
la source
1
Je pense qu'il y a un files.idet blob.fileid. Je suppose que votre requête entraînera une erreur.
jww
-9
delete from table1 t1 
    WHERE not exists (select id from table2 where related_field_in_t2=t1.id) 
    AND not exists (select id from table3 where related_field_in_t3=t1.id) 
    AND not exists (select id from table4 where related_field_t4=t1.id) 
    AND not exists (select id from table5 where related_field_t5=t1.id);
Kamrujjaman Khan
la source
3
J'ai voté contre parce que: 1. Cela ne tente pas de répondre à la question dans le contexte qui a été publié. 2. Il n'y a pas d'explication (et les réponses de code uniquement sont de faible valeur sur Stackoverflow). 3. NOT EXISTSétait déjà publié il y a 9 ans. 4. Vous n'avez pas fait la promotion de la meilleure pratique consistant à utiliser systématiquement toutes les majuscules pour les mots clés MySQL. En d'autres termes, il n'y a rien ici qui vaille la peine d'être gardé - c'est pourquoi j'ai également voté pour supprimer ce message.
mickmackusa