Hapus baris duplikat di MySQL

375

Saya punya tabel dengan bidang-bidang berikut:

id (Unique)
url (Unique)
title
company
site_id

Sekarang, saya perlu menghapus baris yang sama title, company and site_id. Salah satu cara untuk melakukannya adalah menggunakan SQL berikut dengan skrip ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

Setelah menjalankan kueri ini, saya bisa menghapus duplikat menggunakan skrip sisi server.

Tapi, saya ingin tahu apakah ini bisa dilakukan hanya menggunakan query SQL.

Chetan
sumber
1
Pertanyaan cepat: apakah selalu ingin duplikat (judul, perusahaan, site_id) tidak ada? Jika demikian, saya akan membuat batasan dalam database untuk menegakkan judul, perusahaan, dan site_id menjadi unik. Yang berarti Anda tidak perlu proses pembersihan. Dan itu hanya membutuhkan satu baris SQL.
J. Polfer
1
Silakan merujuk tautan stackoverflow ini . Ini berfungsi bagi saya sebagai pesona.
Saya dapat merekomendasikan solusi ini (diposting di utas lain): stackoverflow.com/a/4685232/195835
Simon East
Anda juga dapat memeriksa jawaban ini
Jose Rui Santos

Jawaban:

607

Cara yang sangat mudah untuk melakukan ini adalah dengan menambahkan UNIQUEindeks pada 3 kolom. Saat Anda menulis ALTERpernyataan, sertakan IGNOREkata kunci. Seperti itu:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

Ini akan menghapus semua baris duplikat. Sebagai manfaat tambahan, masa depan INSERTsyang merupakan duplikat akan kesalahan. Seperti biasa, Anda mungkin ingin mengambil cadangan sebelum menjalankan sesuatu seperti ini ...

Chris Henry
sumber
8
Menarik , tetapi asumsi yang dibuat oleh klausa IGNORE untuk menghapus duplikat tersebut adalah masalah yang mungkin tidak sesuai dengan kebutuhan. Nilai-nilai yang salah dipotong ke pertandingan terdekat yang dapat diterima terdengar bagus untuk Anda?
OMG Ponies
75
Sebagai catatan jika Anda menggunakan InnoDB maka Anda mungkin memiliki masalah dengan itu, ada bug yang diketahui tentang menggunakan ALTER IGNORE TABLE dengan database InnoDB.
DarkMantis
27
Bug @DarkMantis yang disebutkan di atas disebut dan solusinya .
Jordan Arseno
42
Untuk tabel InnoDB, jalankan query berikut terlebih dahulu:set session old_alter_table=1;
shock_one
51
Ini tidak lagi mendukung di 5.7.4, dev.mysql.com/doc/refman/5.7/en/alter-table.html
Ray Baxter
180

Jika Anda tidak ingin mengubah properti kolom, maka Anda dapat menggunakan kueri di bawah ini.

Karena Anda memiliki kolom yang memiliki ID unik (misalnya, auto_incrementkolom), Anda dapat menggunakannya untuk menghapus duplikat:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

Di MySQL, Anda dapat lebih menyederhanakannya dengan operator yang setara dengan NULL-safe (alias "operator pesawat ruang angkasa" ):

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;
rehriff
sumber
3
solusi ini tidak berfungsi sebagaimana mestinya, saya mencoba membuat beberapa catatan duplikat dan melakukan sesuatu seperti (20 baris terpengaruh) tetapi jika Anda menjalankannya lagi ia akan menunjukkan kepada Anda (4 baris terpengaruh) dan seterusnya hingga Anda mencapai (0 baris terpengaruh) yang agak mencurigakan dan di sini adalah yang terbaik bagi saya, hampir sama tetapi bekerja dalam satu kali, saya mengedit solusinya
Nassim
1
@Nassim: Anda harus melakukan sesuatu yang berbeda dari jawaban ini karena ini berfungsi sempurna untuk saya (di MySQL).
Lawrence Dol
3
Bagi siapa pun yang bingung seperti saya, syarat perbandingan NULL diperlukan karena NULL tidak sama dengan NULL di MySQL. Jika kolom yang relevan dijamin bukan NULL, Anda dapat mengabaikan persyaratan ini.
Ian
3
Ya, jawaban yang diterima tidak lagi valid, karena MYSQL 5.7 jadi ini harus benar-benar menjadi jawaban yang diterima karena bersifat universal dan tidak memerlukan pembuatan tabel sementara juga.
that-ben
1
SANGAT LAMBAT jika ada BANYAK salinan catatan yang diberikan (misalnya 100 dikurangi menjadi 1), dan banyak catatan dengan kondisi itu. Rekomendasikan stackoverflow.com/a/4685232/199364 sebagai gantinya. IMHO, SELALU menggunakan pendekatan tertaut; ini merupakan teknik yang secara inheren lebih cepat.
ToolmakerSteve
78

MySQL memiliki batasan tentang merujuk ke tabel yang Anda hapus. Anda bisa mengatasinya dengan tabel sementara, seperti:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

Dari saran Kostanos di komentar:
Satu-satunya permintaan lambat di atas adalah DELETE, untuk kasus di mana Anda memiliki database yang sangat besar. Kueri ini bisa lebih cepat:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Andomar
sumber
3
@ Randomar, ini berfungsi dengan baik kecuali ketika salah satu bidang di mana klausa berisi nol. Contoh: sqlfiddle.com/#!2/983f3/1
a coder
1
Apakah Sisipkan SQL itu mahal? Saya bertanya-tanya karena itu habis dalam database MySQL saya.
Cassio
4
Satu-satunya permintaan lambat di sini adalah HAPUS, dalam kasus ketika Anda memiliki database besar. Permintaan ini bisa lebih cepat:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos
@ Kostanos Tidak hanya DELETE, tetapi juga INSERTke meja sementara, saya butuh waktu lama. Jadi indeks untuk tabel tmp bisa banyak membantu create index tmpTable_id_index on tmpTable (id),, setidaknya untuk saya.
Jiezhi.G
1
Jika tabel Anda besar, sebaiknya tambahkan indeks dengan: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke
44

Jika IGNOREpernyataan itu tidak berfungsi seperti dalam kasus saya, Anda dapat menggunakan pernyataan di bawah ini:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;
Kamil
sumber
1
berfungsi dengan baik jika Anda memiliki pengaturan innoDB dengan batasan kunci asing.
magdmartin
@magdmartin, tetapi tidak akan kendala asing mencegah penghapusan tabel?
Basilevs
1
Pernyataan IGNORE tidak berhasil untuk saya dan ini berhasil dengan baik pada pemotongan 5 juta rekaman. Bersulang.
Mauvis Ledford
32

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;
César Revert-Gomar
sumber
27

Ada solusi lain:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...
Mostafa -T
sumber
4
Apa bedanya dengan jawaban @ rehriff, yang ia kirimkan 6 bulan sebelumnya?
Lawrence Dol
@LawrenceDol Saya kira itu sedikit lebih mudah dibaca dan juga saya pikir jawabannya tidak sama pada saat saya menjawab dan saya pikir jawabannya sudah diedit.
Mostafa -T
1
hmm Terlalu lama bagi saya sementara jumlah catatan tidak besar!
SuB
8

jika Anda memiliki tabel besar dengan jumlah record yang sangat besar maka solusi di atas tidak akan berfungsi atau membutuhkan terlalu banyak waktu. Maka kami memiliki solusi yang berbeda

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;
faisalbhagat
sumber
6

Saya punya snipet query ini untuk SQLServer tapi saya pikir ini bisa digunakan di DBMS lain dengan sedikit perubahan:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

Saya lupa memberi tahu Anda bahwa kueri ini tidak menghapus baris dengan id terendah dari baris yang diduplikasi. Jika ini berhasil, Anda dapat mencoba kueri ini:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)
Eduardo Rascon
sumber
Itu tidak akan berhasil jika ada lebih dari dua duplikat grup.
OMG Ponies
11
Sayangnya, MySQL tidak mengizinkan Anda untuk memilih dari tabel yang Anda hapusERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar
1
Untuk mengatasi "You can't specify target table 'Table' for update in FROM..."kesalahan, gunakan: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)yang memaksa MySQL untuk membuat tabel sementara. Namun sangat lambat dalam kumpulan data besar ... dalam kasus seperti itu, saya akan merekomendasikan kode Andomar, yang jauh lebih cepat.
lepe
6

Cara yang lebih cepat adalah memasukkan baris yang berbeda ke tabel sementara. Menggunakan delete, saya butuh beberapa jam untuk menghapus duplikat dari tabel 8 juta baris. Menggunakan insert dan berbeda, hanya butuh 13 menit.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  
Nav
sumber
1
Baris ke-4 Anda seharusnya mengatakan TRUNCATE TABLE tableNamedan baris ke-5 harus mengatakanINSERT INTO tableName SELECT * FROM tempTableName;
Sana
5

Solusi yang mudah dipahami dan bekerja tanpa kunci utama:

1) tambahkan kolom boolean baru

alter table mytable add tokeep boolean;

2) menambahkan batasan pada kolom yang digandakan DAN kolom yang baru

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) setel kolom boolean ke true. Ini akan berhasil hanya pada salah satu baris yang digandakan karena kendala baru

update ignore mytable set tokeep = true;

4) hapus baris yang belum ditandai sebagai tokeep

delete from mytable where tokeep is null;

5) jatuhkan kolom yang ditambahkan

alter table mytable drop tokeep;

Saya menyarankan Anda menjaga batasan yang Anda tambahkan, sehingga duplikat baru dicegah di masa mendatang.

xtian
sumber
1
Ini bekerja sangat baik di mysql 5.7di mana solusi yang diterima tidak berfungsi lagi
Robin31
5

Hapus baris duplikat menggunakan pernyataan DELETE JOIN MySQL memberi Anda pernyataan DELETE JOIN yang dapat Anda gunakan untuk menghapus baris duplikat dengan cepat.

Pernyataan berikut menghapus baris duplikat dan mempertahankan id tertinggi:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;
Saad Mirza
sumber
5

Saya menemukan cara sederhana. (tetap terbaru)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;
Rico Nguyen
sumber
4

Sederhana dan cepat untuk semua kasus:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);
artemiuz
sumber
Kode Kesalahan: 1055. Ekspresi # 2 dari daftar SELECT tidak dalam klausa GROUP BY dan berisi kolom 'dub.id' yang tidak diagregasi yang tidak secara fungsional bergantung pada kolom dalam klausa GROUP BY; ini tidak kompatibel dengan sql_mode = only_full_group_by
Swoogan
Anda dapat menonaktifkan "kontrol keras" dengan sql_mode, lihat stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz
4

Ini akan menghapus baris duplikat dengan nilai yang sama untuk judul, perusahaan dan situs. Kejadian pertama akan disimpan dan sisanya semua duplikat akan dihapus

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;
Dhrumil Panchal
sumber
lambat (baris 5w +, waktu tunggu tunggu kunci) tetapi berhasil
yurenchen
3

Saya terus mengunjungi halaman ini kapan saja saya google "menghapus duplikat formulir mysql" tetapi untuk solusi theIGNORE saya tidak berfungsi karena saya memiliki tabel mysql InnoDB

kode ini berfungsi lebih baik kapan saja

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = nama tabel yang perlu Anda bersihkan

tableToclean_temp = tabel sementara dibuat dan dihapus

Francesco
sumber
2

Solusi ini akan memindahkan duplikat ke satu tabel dan yang unik ke yang lain .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs
Anthony Vipond
sumber
Mengapa Anda mengambil persatuan dan bukan hanya SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran
2

Pada versi 8.0 (2018), MySQL akhirnya mendukung fungsi jendela .

Fungsi jendela berguna dan efisien. Berikut adalah solusi yang menunjukkan cara menggunakannya untuk menyelesaikan tugas ini.

Dalam subquery, kita bisa menggunakan ROW_NUMBER()untuk menetapkan posisi untuk setiap catatan dalam tabel dalam column1/column2kelompok, yang dipesan oleh id. Jika tidak ada duplikat, catatan akan mendapatkan nomor baris 1. Jika duplikat ada, mereka akan diberi nomor dengan naik id(mulai dari 1).

Setelah catatan diberi nomor dengan benar dalam subquery, permintaan luar hanya menghapus semua catatan yang nomor barisnya bukan 1.

Pertanyaan:

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)
GMB
sumber
1

Untuk menghapus catatan duplikat dalam sebuah tabel.

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

atau

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);
Arun Solomon
sumber
1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;
Duy Hoang
sumber
0

Agar dapat menggandakan rekaman dengan kolom unik, misalnya COL1, COL2, COL3 tidak boleh direplikasi (misalkan kita telah melewatkan 3 kolom yang unik dalam struktur tabel dan beberapa entri duplikat telah dibuat ke dalam tabel)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

Semoga akan membantu dev.

Abdul Rehman
sumber
0

TL; TR;

Tutorial yang sangat dijelaskan untuk mengatasi masalah ini dapat ditemukan di situs mysqltutorial.org :

Cara Menghapus Baris Duplikat di MySQL

Sangat jelas ditunjukkan cara menghapus duplikat baris dalam tiga cara berbeda :

A) Menggunakan DELETE JOINpernyataan

B) Menggunakan tabel perantara

C) Menggunakan ROW_NUMBER()fungsi

Saya harap ini akan membantu seseorang.

simhumileco
sumber
0

Saya punya tabel yang lupa menambahkan kunci utama di baris id. Meskipun memiliki auto_increment pada id. Tetapi suatu hari, satu hal memutar ulang log mysql bin pada database yang menyisipkan beberapa baris duplikat.

Saya menghapus baris duplikat oleh

  1. pilih baris duplikat unik dan ekspor

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. hapus duplikat baris oleh id

  2. masukkan baris dari data yang diekspor.

  3. Kemudian tambahkan kunci utama pada id

Kris Roofe
sumber
-2

Saya ingin sedikit lebih spesifik tentang catatan yang saya hapus jadi di sini adalah solusi saya:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)
Michael Tel
sumber
-4

Anda dapat dengan mudah menghapus rekaman duplikat dari kode ini ..

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}
Syed Amir Bukhari
sumber
3
Ini adalah form-database tugas yang sangat buruk harus dilakukan dalam DB, di mana mereka jauh lebih cepat, daripada mengirim data secara konstan antara php / mysql karena Anda tahu yang lebih baik daripada yang lain.
Maks
-4

Saya harus melakukan ini dengan bidang teks dan menemukan batas 100 byte pada indeks.

Saya memecahkan ini dengan menambahkan kolom, melakukan hash md5 dari bidang, dan melakukan alter.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
Sunil
sumber