Usuń wiersze sql, w przypadku których identyfikatory nie pasują do innej tabeli

160

Próbuję usunąć osierocone wpisy w tabeli mysql.

Mam 2 takie tabele:

Tabela files:

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

stół blob:

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

Do łączenia tabel można użyć kolumn fileidi id.

Chcę usunąć wszystkie wiersze w tabeli, blobktórych fileidnie można znaleźć w tabeli files.id.

Korzystając z powyższego przykładu, można usunąć wiersze: 3 i 4 (y) w blobtabeli.

Jaskółka oknówka
źródło
1
Przejdź do drugiej odpowiedzi, jeśli używasz nulls.
Pacerier,

Odpowiedzi:

327

Używanie LEFT JOIN / IS NULL:

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

Korzystanie NIE ISTNIEJE:

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

Korzystanie NOT IN:

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

Ostrzeżenie

O ile to możliwe, wykonaj DELETE w ramach transakcji (zakładając, że jest obsługiwana - IE: nie w MyISAM), aby móc użyć wycofywania zmian w celu cofnięcia zmian w przypadku problemów.

Kucyki OMG
źródło
12
który jest na ogół najszybszy z powyższych?
Hampus Brynolf
2
Z jakiegoś powodu usuwanie za pomocą LEFT JOIN nie działało na MS SQL Server Mgmt Studio (nie wiem dlaczego; po prostu narzekał na LEFT JOIN). Czy ktoś wie, dlaczego tak jest? Zadziałało przy użyciu NIE ISTNIEJE :)
Anna
5
Do Twojej wiadomości, oto pożyteczna dyskusja na temat względnej skuteczności tych trzech metod: wyjaśnieniextended.com
09/18/ ...
2
@Pacerier - „źle” jest trochę mocne. Aby upewnić się, że ludzie rozumieją, odpowiedzi wykonać pracę, jeśli fileidjest bez pustych . Ponadto trzecie rozwiązanie ( NOT IN) wymaga tylko tego, aby f.idnie dopuszczać wartości null. Przypuszczalnie jest to klucz podstawowy, więc tak by było.
ToolmakerSteve
2
Dla osób próbujących tego w / SQLite: zobacz tę odpowiedź
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
źródło
Co to jest „/ * Ta linia prawdopodobnie nie będzie potrzebna, ale użycie NOT IN ... * /” powinno oznaczać?
Pacerier,
1
@Pacerier - NOT IN (NULL)zwraca pusty zestaw wyników, więc należy wykluczyć wartości NULL. Ale idkolumna prawdopodobnie i tak nie będzie miała wartości null, stąd „raczej nie będzie potrzebna”
Martin Smith
Wow, dobry chwyt. Więc odpowiedź omgponies jest błędna! not in(null)jest całkiem logiczne, dlaczego nie działa? Jaki jest tego powód?
Pacerier,
1
@bunkerdive Następnie użyj trzyczęściowych nazw obiektów, które zawierają nazwę bazy danych.
Martin Smith
17
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
Jerzy
źródło
1
Myślę, że jest files.idi blob.fileid. Zgaduję, że twoje zapytanie spowoduje błąd.
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
źródło
3
Oddałem głos, ponieważ: 1. To nie jest próbą odpowiedzi na pytanie w kontekście, który został opublikowany. 2. Nie ma żadnego wyjaśnienia (a odpowiedzi zawierające tylko kod mają niską wartość w Stackoverflow). 3. NOT EXISTSzostał opublikowany już 9 lat temu. 4. Nie promowałeś najlepszej praktyki polegającej na konsekwentnym używaniu wielkich liter w słowach kluczowych MySQL. Innymi słowy, nie ma tu nic wartego zachowania - dlatego też głosowałem za usunięciem tego posta.
mickmackusa