Löschen Sie SQL-Zeilen, bei denen IDs nicht mit einer anderen Tabelle übereinstimmen

159

Ich versuche, verwaiste Einträge in einer MySQL-Tabelle zu löschen.

Ich habe 2 Tabellen wie diese:

Tabelle files:

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

Tabelle blob:

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

Die Spalten fileidund idkönnen verwendet werden, um die Tabellen miteinander zu verbinden.

Ich möchte alle Zeilen in der Tabelle löschen , blobwo fileidnicht in der Tabelle zu finden files.id.

Verwenden Sie also das obige Beispiel, um die Zeilen zu löschen: 3 & 4 (s) in der blobTabelle.

Martin
quelle
1
Fahren Sie mit der zweiten Antwort fort, wenn Sie nulls verwenden.
Pacerier

Antworten:

326

Verwenden von LEFT JOIN / IS NULL:

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

Verwenden von NOT EXISTS:

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

Verwenden von NOT IN:

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

Warnung

Führen Sie nach Möglichkeit DELETEs innerhalb einer Transaktion aus (vorausgesetzt, unterstützt - IE: Nicht unter MyISAM), damit Sie bei Problemen mithilfe des Rollbacks Änderungen rückgängig machen können.

OMG Ponys
quelle
12
Welches ist im Allgemeinen das schnellste der oben genannten?
Hampus Brynolf
2
Aus irgendeinem Grund funktionierte das Löschen mit LEFT JOIN unter MS SQL Server Mgmt Studio nicht (nicht sicher warum; es wurde nur über LEFT JOIN geklagt). Weiß jemand warum das so ist? Es hat mit NOT EXISTS funktioniert :)
Anna
5
Zu
Ihrer Information
2
@ Pacerier - "falsch" ist ein bisschen stark. Um sicherzustellen , dass die Menschen verstehen, die Antworten zu tun Arbeit , wenn fileidist nicht nullable . Auch die dritte Lösung ( NOT IN) erfordert nur, dass f.idnicht nullbar. Vermutlich ist das ein Primärschlüssel, also wäre es.
ToolmakerSteve
2
Für Leute, die dies mit SQLite versuchen: siehe diese Antwort
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
quelle
Was ist "/ * Diese Zeile wird wahrscheinlich nicht benötigt, aber die Verwendung von NOT IN ... * /" soll bedeuten?
Pacerier
1
@Pacerier - Gibt NOT IN (NULL)eine leere Ergebnismenge zurück, sodass NULL-Werte ausgeschlossen werden müssen. Aber eine idSpalte wird wahrscheinlich sowieso nicht nullbar sein, daher "wahrscheinlich nicht benötigt"
Martin Smith
Wow guter Fang. Die Antwort von Omgponys ist also falsch! not in(null)ist ziemlich logisch, warum funktioniert es nicht? Was ist der Grund dafür?
Pacerier
1
@bunkerdive Verwenden Sie dann dreiteilige Objektnamen, die den Datenbanknamen enthalten.
Martin Smith
17
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
George
quelle
1
Ich denke es gibt ein files.idund blob.fileid. Ich vermute, Ihre Anfrage wird zu einem Fehler führen.
JWW
-8
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
quelle
3
Ich habe abgestimmt, weil: 1. Dies versucht nicht, die Frage in dem Kontext zu beantworten, der veröffentlicht wurde. 2. Es gibt keine Erklärung (und Nur-Code-Antworten sind bei Stackoverflow von geringem Wert). 3. NOT EXISTSwurde bereits vor 9 Jahren veröffentlicht. 4. Sie haben nicht für die bewährte Methode geworben, All-Caps für MySQL-Schlüsselwörter konsequent zu verwenden. Mit anderen Worten, hier gibt es nichts, was es wert wäre, behalten zu werden - deshalb habe ich auch dafür gestimmt, diesen Beitrag zu löschen.
Mickmackusa