Menghapus duplikat pada tabel MySQL adalah masalah umum, itu secara umum merupakan hasil dari kendala yang hilang untuk menghindari duplikat tersebut sebelumnya. Tetapi masalah umum ini biasanya datang dengan kebutuhan spesifik ... yang memang membutuhkan pendekatan khusus. Pendekatan harus berbeda tergantung pada, misalnya, ukuran data, entri yang digandakan yang harus disimpan (umumnya yang pertama atau yang terakhir), apakah ada indeks yang akan disimpan, atau apakah kita ingin melakukan tambahan tindakan pada data yang digandakan.
Ada juga beberapa kekhususan pada MySQL itu sendiri, seperti tidak dapat mereferensikan tabel yang sama pada penyebab FROM saat melakukan UPDATE tabel (itu akan meningkatkan kesalahan MySQL # 1093). Batasan ini dapat diatasi dengan menggunakan kueri dalam dengan tabel sementara (seperti yang disarankan pada beberapa pendekatan di atas). Tetapi permintaan dalam ini tidak akan bekerja dengan baik ketika berhadapan dengan sumber data besar.
Namun, pendekatan yang lebih baik memang ada untuk menghapus duplikat, itu efisien dan dapat diandalkan, dan yang dapat dengan mudah disesuaikan dengan kebutuhan yang berbeda.
Gagasan umum adalah membuat tabel sementara baru, biasanya menambahkan batasan unik untuk menghindari duplikat lebih lanjut, dan untuk menyisipkan data dari tabel Anda sebelumnya ke yang baru, sambil menjaga duplikat. Pendekatan ini bergantung pada permintaan MySQL INSERT sederhana, menciptakan kendala baru untuk menghindari duplikat lebih lanjut, dan melompati kebutuhan menggunakan kueri batin untuk mencari duplikat dan tabel sementara yang harus disimpan dalam memori (sehingga menyesuaikan sumber data besar juga).
Ini adalah bagaimana hal itu dapat dicapai. Mengingat kami memiliki karyawan meja , dengan kolom berikut:
employee (id, first_name, last_name, start_date, ssn)
Untuk menghapus baris dengan kolom duplikat ssn , dan hanya menyimpan entri pertama yang ditemukan, proses berikut dapat diikuti:
-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;
-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;
-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
Penjelasan teknis
- Baris # 1 membuat tabel tmp_eployee baru dengan struktur yang persis sama dengan tabel karyawan
- Baris # 2 menambahkan batasan UNIK ke tabel tmp_eployee baru untuk menghindari duplikat lebih lanjut
- Baris # 3 memindai tabel karyawan asli dengan id, menyisipkan entri karyawan baru ke dalam tabel tmp_eployee baru , sementara mengabaikan entri yang digandakan
- Baris # 4 mengganti nama tabel, sehingga tabel karyawan baru menyimpan semua entri tanpa duplikat, dan salinan cadangan dari data sebelumnya disimpan di tabel backup_employee
⇒ Dengan menggunakan pendekatan ini, register 1,6M dikonversi menjadi 6k dalam waktu kurang dari 200an.
Chetan , mengikuti proses ini, Anda bisa dengan cepat dan mudah menghapus semua duplikat Anda dan membuat batasan UNIK dengan menjalankan:
CREATE TABLE tmp_jobs LIKE jobs;
ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);
INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;
RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;
Tentu saja, proses ini dapat dimodifikasi lebih lanjut untuk menyesuaikannya dengan kebutuhan yang berbeda saat menghapus duplikat. Beberapa contoh mengikuti.
✔ Variasi untuk menjaga entri terakhir, bukan yang pertama
Kadang-kadang kita perlu menyimpan entri yang digandakan terakhir daripada yang pertama.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- Pada baris # 3, klausa ORDER BY id DESC membuat ID terakhir untuk mendapatkan prioritas daripada yang lain
✔ Variasi untuk melakukan beberapa tugas pada duplikat, misalnya menjaga hitungan pada duplikat yang ditemukan
Terkadang kita perlu melakukan beberapa pemrosesan lebih lanjut pada entri yang digandakan yang ditemukan (seperti menjaga jumlah duplikat).
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;
INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- Pada baris # 3, kolom baru n_duplikat dibuat
- Pada baris # 4, INSERT INTO ... ON DUPLICATE KEY UPDATE query digunakan untuk melakukan pembaruan tambahan ketika duplikat ditemukan (dalam hal ini, menambah penghitung) INSERT INTO ... ON DUPLICATE KEY UPDATE query dapat berupa digunakan untuk melakukan berbagai jenis pembaruan untuk duplikat yang ditemukan.
✔ Variasi untuk meregenerasi id bidang penambahan-otomatis
Kadang-kadang kita menggunakan bidang penambahan otomatis dan, agar indeks tetap seringkas mungkin, kita bisa memanfaatkan penghapusan duplikat untuk membuat ulang bidang penambahan otomatis di tabel sementara yang baru.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- Pada baris # 3, alih-alih memilih semua bidang di atas meja, bidang id dilewati sehingga mesin DB menghasilkan yang baru secara otomatis
✔ Variasi lebih lanjut
Banyak modifikasi lebih lanjut juga dapat dilakukan tergantung pada perilaku yang diinginkan. Sebagai contoh, kueri berikut akan menggunakan tabel sementara kedua, selain 1) menyimpan entri terakhir, bukan yang pertama; dan 2) menambah penghitung pada duplikat yang ditemukan; juga 3) meregenerasi id bidang penambahan otomatis sambil tetap menjaga urutan entri seperti pada data sebelumnya.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;
INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;
CREATE TABLE tmp_employee2 LIKE tmp_employee;
INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;
DROP TABLE tmp_employee;
RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;