Hapus baris sql di mana ID tidak memiliki kecocokan dari tabel lain

160

Saya mencoba menghapus entri anak yatim di tabel mysql.

Saya punya 2 tabel seperti ini:

Meja files:

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

meja blob:

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

The fileiddan idkolom dapat digunakan untuk bergabung dengan tabel bersama-sama.

Saya ingin menghapus semua baris dalam tabel di blobmana fileidtidak dapat ditemukan dalam tabel files.id.

Jadi, gunakan contoh di atas yang akan menghapus baris: 3 & 4 (s) dalam blobtabel.

Martin
sumber
1
Lewati ke jawaban kedua jika Anda menggunakan nulls.
Pacerier

Jawaban:

327

Menggunakan LEFT JOIN / IS NULL:

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

Menggunakan BUKAN ADA:

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

Menggunakan TIDAK DALAM:

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

Peringatan

Kapan pun memungkinkan, lakukan DELETE dalam suatu transaksi (dengan asumsi didukung - IE: Not on MyISAM) sehingga Anda dapat menggunakan rollback untuk mengembalikan perubahan jika terjadi masalah.

OMG Ponies
sumber
12
yang mana, secara umum, yang tercepat di atas?
Hampus Brynolf
2
Untuk beberapa alasan, menghapus menggunakan LEFT JOIN tidak berfungsi pada MS SQL Server Mgmt Studio (tidak yakin mengapa; itu hanya mengeluhkan LEFT JOIN). Adakah yang tahu kenapa begitu? Itu bekerja menggunakan TIDAK ADA :):
Anna
5
FYI, inilah diskusi yang berguna efisiensi relatif dari ketiga metode: explainextended.com/2009/09/18/...
Moustachio
2
@Pacerier - "salah" agak kuat. Untuk memastikan orang mengerti, jawaban melakukan pekerjaan jika fileidadalah non-nullable . Juga, solusi ketiga ( NOT IN) hanya membutuhkan f.idnon-nullable. Agaknya itu adalah kunci utama, jadi itu akan menjadi.
ToolmakerSteve
2
Untuk orang yang mencoba ini dengan SQLite: lihat jawaban ini
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
sumber
Apa itu "/ * Baris ini tidak mungkin diperlukan tetapi menggunakan TIDAK DI ... * /" seharusnya berarti?
Pacerier
1
@Pacerier - NOT IN (NULL)mengembalikan set hasil kosong sehingga NULL perlu dikecualikan. Namun idkolom mungkin tidak akan dibatalkan karena itu "tidak diperlukan"
Martin Smith
Wow tangkapan yang bagus. Jadi jawaban omgponies salah! not in(null)cukup logis, Mengapa itu tidak berhasil? Apa alasan di balik itu?
Pacerier
1
@ Bunkerdive Kemudian gunakan tiga nama objek bagian yang menyertakan nama database.
Martin Smith
17
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
George
sumber
1
Saya pikir ada files.iddan blob.fileid. Saya menduga permintaan Anda akan menghasilkan kesalahan.
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
sumber
3
Saya telah menurunkan suara karena: 1. Ini tidak berusaha menjawab pertanyaan dalam konteks yang diposting. 2. Tidak ada penjelasan (dan jawaban hanya kode bernilai rendah di Stackoverflow). 3. NOT EXISTSsudah diposting 9 tahun yang lalu. 4. Anda belum mempromosikan praktik terbaik menggunakan huruf kapital MySQL secara konsisten. Dengan kata lain, tidak ada yang layak dipertahankan di sini - inilah sebabnya saya juga memilih untuk menghapus posting ini.
mickmackusa