Hapus dengan Bergabung di MySQL

501

Berikut ini skrip untuk membuat tabel saya:

CREATE TABLE clients (
   client_i INT(11),
   PRIMARY KEY (client_id)
);
CREATE TABLE projects (
   project_id INT(11) UNSIGNED,
   client_id INT(11) UNSIGNED,
   PRIMARY KEY (project_id)
);
CREATE TABLE posts (
   post_id INT(11) UNSIGNED,
   project_id INT(11) UNSIGNED,
   PRIMARY KEY (post_id)
);

Dalam kode PHP saya, ketika menghapus klien, saya ingin menghapus semua posting proyek:

DELETE 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

Tabel posting tidak memiliki kunci asing client_id, hanya project_id. Saya ingin menghapus posting di proyek yang telah lulus client_id.

Ini tidak berfungsi sekarang karena tidak ada posting yang dihapus.

GeekJock
sumber
10
Saya pikir jawaban Yehosef harus yang diterima, karena dia menggunakan Gabung seperti yang Anda minta dan itu berkinerja lebih baik daripada menggunakan klausa IN seperti yang diusulkan yukondude ...
Gerardo Grignoli
2
Pola yang disukai adalah a DELETE posts FROM posts JOIN projects ..., bukan IN (subquery)pola. (Jawaban dari Yehosef memberikan contoh pola yang disukai.)
spencer7593
@ GerardoGrignoli, berkinerja lebih baik untuk mesin atau versi MySQL tertentu? Tidak ada alasan mengapa dua kueri melakukan yang berbeda, karena AFAIK mereka identik. Tentu saja, jika saya punya nikel untuk setiap kali optimizer kueri saya melakukan sesuatu yang bodoh ....
Paul Draper
Anda juga dapat menggunakan aliasuntuk nama tabel dan menggunakannya.
biniam

Jawaban:

1254

Anda hanya perlu menentukan bahwa Anda ingin menghapus entri dari poststabel:

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

EDIT: Untuk informasi lebih lanjut Anda dapat melihat jawaban alternatif ini

Yehosef
sumber
117
Perlu dicatat bahwa ini adalah jawaban yang benar karena bergabung memaksa Anda untuk menggunakan "HAPUS posting DARI posting" bukannya "DELETE DARI posting" normal, karena tabel untuk menghapus tidak lagi ambigu. Terima kasih!
siannopollo
8
Catatan Anda tidak dapat menggunakan metode 'sebagai' di sini misalnya proyek gabungan dalam sebagai p di p.project_id ...
zzapper
14
Sebenarnya Anda bisa menggunakan alias untuk tabel bergabung, tetapi tidak untuk tabel utama (posting). "HAPUS kiriman DARI Kiriman INNER GABUNG proyek p ON p.project_id = posts.project_id"
Weboide
85
"Jika Anda mendeklarasikan alias untuk sebuah tabel, Anda harus menggunakan alias saat merujuk ke tabel" seperti ituDELETE d FROM posts AS d JOIN projects AS p ON ...
KCD
14
ini adalah jawaban terbaik karena Anda bahkan dapat menghapus dari kedua tabel dalam satu tindakanDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Karena Anda memilih beberapa tabel, Tabel yang akan dihapus tidak lagi ambigu. Anda harus memilih :

DELETE posts FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

Dalam hal ini, table_name1dan table_name2merupakan tabel yang sama, maka ini akan berfungsi:

DELETE projects FROM posts INNER JOIN [...]

Anda bahkan dapat menghapus dari kedua tabel jika Anda ingin:

DELETE posts, projects FROM posts INNER JOIN [...]

Perhatikan itu order bydan limit tidak berfungsi untuk penghapusan multi-tabel .

Perlu diketahui juga bahwa jika Anda mendeklarasikan alias untuk suatu tabel, Anda harus menggunakan alias saat merujuk ke tabel:

DELETE p FROM posts as p INNER JOIN [...]

Kontribusi dari Carpetsmoker dan lain-lain .

Pacerier
sumber
3
Jika Anda membuat jawaban yang lebih baik - setidaknya Anda bisa membuat SQL lebih mudah dibaca. Semua referensi SQL lain dalam pertanyaan ini memiliki huruf besar dengan kata kunci (kecuali satu dengan 0 suara). Saya tidak yakin mengapa Anda mengembalikan suntingan saya.
Yehosef
3
@Yehosef, Ada sekelompok orang yang menemukan CAPS benar-benar mencolok. Saya percaya saya bukan satu-satunya, saya telah melihat beberapa orang menggunakan huruf kecil juga.
Pacerier
1
cukup adil - Saya menghormati hak Anda untuk menulis jawaban Anda dengan gaya yang Anda sukai;)
Yehosef
7
Untuk menambah diskusi caps / no caps, benar, Anda dapat menggunakan gaya apa pun yang Anda suka, tetapi dalam jawaban Anda, Anda sebenarnya mencampur gaya di mana Anda merasa nyaman - huruf ONkapital. Untuk pengembang yang kurang berpengalaman, mungkin menyampaikan bahwa tidak masalah berantakan dan tidak konsisten dalam hal gaya.
Shade
16
KATA KUNCI CAPS tidak melotot. mereka MEMBUAT QUERIES READABLE;)
Sachem
50

Atau hal yang sama, dengan sintaks (IMO lebih ramah) sedikit berbeda:

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

BTW, dengan mysql menggunakan bergabung hampir selalu jauh lebih cepat daripada subqueries ...

ivanhoe
sumber
Apa arti USING?
CMCDragonkai
1
Penjelasan bagus tentang USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Harap perhatikan bahwa kata kunci MENGGUNAKAN dalam pernyataan SELECT tidak ada hubungannya dengan kata kunci yang sama dalam pernyataan DELETE. Dalam SELECT, ini menentukan daftar kolom untuk bergabung, sementara di DELETE itu adalah daftar semua tabel dalam sebuah gabungan
ivanhoe
42

Anda juga dapat menggunakan ALIAS seperti ini berfungsi hanya menggunakannya di database saya! t adalah tabel yang perlu dihapus!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Properti Spanyol
sumber
1
ini berguna pada gabungan kunci gabungan untuk menghindari pengulangan nama tabel
Marquez
1
"Sebenarnya Anda dapat menggunakan alias untuk tabel bergabung, tetapi tidak untuk tabel utama (posting). 'HAPUS posting DARI posting proyek INNER JOIN p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert
2
Sebenarnya (mengutip dari dev.mysql.com/doc/refman/5.0/id/delete.html ) "Jika Anda mendeklarasikan alias untuk sebuah tabel, Anda harus menggunakan alias saat merujuk ke tabel: DELETE t1 FROM test AS t1, test2 WHERE ... "jadi menggunakan alias tidak masalah.
Peter Bowers
25

Saya lebih terbiasa dengan solusi subquery untuk ini, tapi saya belum mencobanya di MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
Yukondude
sumber
85
Anda harus benar-benar menghindari menggunakan kata kunci IN dalam SQL (meskipun biasanya lebih mudah dipahami untuk pemula) dan menggunakan BERGABUNG sebagai gantinya (bila mungkin), karena subqueries biasanya membuat banyak hal lebih lambat.
user276648
14
Ini cenderung merusak DB ketika ada sejumlah besar baris yang dikembalikan oleh permintaan sub. Ini juga sangat lambat.
Raj
2
@yukondude Memang "IN" jauh lebih mudah dipahami daripada "BERGABUNG" pada tanggal 1, dan itulah sebabnya orang-orang yang tidak terlalu akrab dengan SQL akan akhirnya menulis "IN" di mana-mana, sementara mereka bisa menggunakan "GABUNG" yang berkinerja lebih baik ( atau banyak yang lebih baik, tergantung pada permintaan). Saya ingat beberapa tahun yang lalu, hampir semua pertanyaan SQL saya akan ditulis ulang oleh seseorang yang benar-benar tahu cara menulis pertanyaan yang bagus. Itu sebabnya saya menambahkan komentar untuk menghindari "IN", sehingga orang akan tahu bahwa jika mungkin, mereka harus menghindari menggunakannya.
user276648
10
Alasan saya datang ke halaman ini adalah karena kueri yang saya tulis dengan pernyataan IN sangat lambat. Hindari jawaban yang diterima di sini.
MikeKulls
4
Setua pertanyaan ini, penting untuk mengetahui MENGAPA Anda harus menggunakan GABUNG alih-alih DALAM. Ketika kondisi di mana berjalan pada baris, itu akan menjalankan permintaan itu di dalam IN. Itu berarti, jika ada 100 baris yang perlu diperiksa terhadap WHERE itu, subquery yang akan dijalankan 100 kali. Sedangkan GABUNG hanya akan berjalan SEKALI. Jadi, saat db Anda semakin besar dan lebih besar, kueri itu akan memakan waktu lebih lama dan lebih lama untuk selesai. @markus hanya karena ada sesuatu yang tidak penting tidak berarti Anda harus menulis kode yang buruk. Menulisnya sedikit lebih baik akan menghemat banyak waktu dan sakit kepala di masa depan. :)
RisingSun
11

Catatan DELETE MySQL dengan GABUNG

Anda biasanya menggunakan INNER BERGABUNG dalam pernyataan SELECT untuk memilih catatan dari tabel yang memiliki catatan yang sesuai di tabel lain. Kami juga bisa menggunakan klausa INNER JOIN dengan pernyataan DELETE untuk menghapus rekaman dari tabel dan juga catatan yang sesuai di tabel lain misalnya, untuk menghapus catatan dari tabel T1 dan T2 yang memenuhi kondisi tertentu, Anda menggunakan pernyataan berikut:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Perhatikan bahwa Anda meletakkan nama tabel T1 dan T2 antara DELETE dan FROM. Jika Anda menghilangkan tabel T1, pernyataan DELETE hanya menghapus catatan di tabel T2, dan jika Anda menghilangkan tabel T2, hanya catatan di tabel T1 yang dihapus.

Kondisi gabungan T1.key = T2.key menentukan catatan yang sesuai dalam tabel T2 yang perlu dihapus.

Kondisi dalam klausa WHERE menentukan catatan mana dalam T1 dan T2 yang perlu dihapus.

Aman Garg
sumber
11

Hapus Tabel Tunggal:

Untuk menghapus entri dari poststabel:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Untuk menghapus entri dari projectstabel:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Untuk menghapus entri dari clientstabel:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Hapus Beberapa Tabel:

Untuk menghapus entri dari beberapa tabel dari hasil yang digabungkan, Anda perlu menentukan nama tabel setelah DELETEdaftar yang dipisahkan koma:

Misalkan Anda ingin menghapus entri dari semua tiga tabel ( posts, projects, clients) untuk klien tertentu:

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id
1000111
sumber
7

Coba seperti di bawah ini:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;
Sangeetha Narayana Moorthy
sumber
4

Metode lain untuk menghapus menggunakan sub pilih yang lebih baik daripada menggunakan INakanWHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

Salah satu alasan untuk menggunakan ini daripada bergabung adalah bahwa DELETEdengan JOINmelarang penggunaan LIMIT. Jika Anda ingin menghapus dalam blok agar tidak menghasilkan kunci tabel penuh, Anda bisa menambahkan LIMITmenggunakan DELETE WHERE EXISTSmetode ini .

Jim Clouse
sumber
1
Bisakah kueri ini ditulis dengan "alias"? Tidak terlalu jelas dari sintaks bagaimana postsEXISTS dalam () adalah sama postsdengan baris yang dihapus. (
Lagipula
Saya mendengar Anda, tetapi alias tidak diizinkan di tabel untuk dihapus. "Posting" di sub kueri harus berupa nama tabel lengkap, yang berarti bahwa jika Anda ingin menggunakan kembali tabel itu di sub-pilih Dari klausa, Anda harus menambahkannya di sana.
Jim Clouse
1
Ini bekerja:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco
4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

HAPUS catatan dari satu tabel:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

HAPUS RECORDS DARI kedua tabel:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);
zloctb
sumber
1

Jika bergabung tidak bekerja untuk Anda, Anda dapat mencoba solusi ini. Ini untuk menghapus catatan anak yatim dari t1 ketika tidak menggunakan kunci asing + kondisi khusus. Yaitu menghapus catatan dari table1, yang memiliki "kode" bidang kosong dan yang tidak memiliki catatan di table2, cocok dengan bidang "nama".

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);
Kristjan Adojaan
sumber
0

Coba ini,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id
Silambarasan
sumber
-3

- Perhatikan bahwa Anda tidak dapat menggunakan alias di atas tabel tempat Anda perlu menghapus

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50
Hernan Torres
sumber