Bagaimana menemukan duplikat dalam 2 kolom bukan 1

107

Saya memiliki tabel database MySQL dengan dua kolom yang menarik minat saya. Secara individual mereka masing-masing dapat memiliki duplikat, tetapi mereka tidak boleh memiliki duplikat KEDUA dari mereka yang memiliki nilai yang sama.

stone_iddapat memiliki duplikat selama untuk setiap upshargejudul berbeda, dan sebaliknya. Tetapi katakanlah misalnya stone_id= 412 dan upcharge_title= "safir" bahwa kombinasi hanya boleh muncul sekali.

Ini bagus:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "ruby"

Ini TIDAK OK:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "sapphire"

Apakah ada kueri yang akan menemukan duplikat di kedua bidang? Dan jika memungkinkan, adakah cara untuk mengatur basis data saya agar tidak mengizinkannya?

Saya menggunakan MySQL versi 4.1.22

JD Isaacks
sumber

Jawaban:

192

Anda harus menyiapkan kunci komposit di antara dua bidang. Ini akan membutuhkan stone_id dan upcharge_title yang unik untuk setiap baris.

Sejauh menemukan duplikat yang ada, coba ini:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1
Miyagi Coder
sumber
Terima kasih, itu memilih mereka. Bisakah Anda berbaik hati memberi tahu saya cara menghapus duplikat (tetapi tinggalkan 1 salinan saja) TERIMA KASIH !!
JD Isaacks
2
Salah satu caranya adalah dengan mengambil semua data yang berbeda dan membuat ulang tabelnya.
Miyagi Coder
1
@ John Isaacks: Jika tidak ada bidang lain yang dapat Anda gunakan untuk membedakannya (yaitu semua bidang adalah duplikat), maka Anda harus menghapus kedua baris & membuatnya kembali. Salah satu caranya adalah dengan menyalin duplikat ke dalam salinan tabel, menghapusnya dari aslinya, & memasukkan kembali baris yang berbeda dari salinannya.
P Daddy
Ini tidak berfungsi pada postgres 8.1, dapatkah seseorang membantu saya?
Lennon
Terima kasih banyak, apakah urutan yang Anda kelompokkan berdasarkan masalah?
Andrew
35

Saya merasa terbantu untuk menambahkan indeks unqiue menggunakan "ALTER IGNORE" yang menghapus duplikat dan memberlakukan catatan unik yang sepertinya ingin Anda lakukan. Jadi sintaksnya adalah:

ALTER IGNORE TABLE `table` ADD UNIQUE INDEX(`id`, `another_id`, `one_more_id`);

Ini secara efektif menambahkan batasan unik yang berarti Anda tidak akan pernah memiliki catatan duplikat dan ABAIKAN menghapus duplikat yang ada.

Anda dapat membaca lebih lanjut tentang eh ALTER IGNORE di sini: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

Pembaruan: Saya diberitahu oleh @Inquisitive bahwa ini mungkin gagal di versi MySql> 5.5:

Gagal Pada MySQL> 5.5 dan pada tabel InnoDB, dan di Percona karena fitur pembuatan indeks cepat InnoDB mereka [ http://bugs.mysql.com/bug.php?id=40344] . Dalam hal ini jalankan pertama set session old_alter_table=1dan kemudian perintah di atas akan berfungsi dengan baik

Pembaruan - ALTER IGNOREDihapus di 5.7

Dari dokumen

Pada MySQL 5.6.17, klausa IGNORE sudah tidak digunakan lagi dan penggunaannya menghasilkan peringatan. IGNORE dihapus di MySQL 5.7.

Salah satu pengembang MySQL memberikan dua alternatif :

  • Kelompokkan menurut bidang unik dan hapus seperti yang terlihat di atas
  • Buat tabel baru, tambahkan indeks unik, gunakan INSERT IGNORE, mis:
CREATE TABLE duplicate_row_table LIKE regular_row_table;
ALTER TABLE duplicate_row_table ADD UNIQUE INDEX (id, another_id);
INSERT IGNORE INTO duplicate_row_table SELECT * FROM regular_row_table;
DROP TABLE regular_row_table;
RENAME TABLE duplicate_row_table TO regular_row_table;

Tetapi tergantung pada ukuran meja Anda, ini mungkin tidak praktis

SeanDowney
sumber
1
Benar, tapi setidaknya untuk lain kali Anda tahu. Saya memiliki masalah yang sama dan menurut saya bagus untuk berbagi dengan orang lain
SeanDowney
Saya hanya menggoda tentang itu karena terlambat 3 tahun. Sangat senang Anda berbagi. Oleh karena itu plus 1.
JD Isaacks
Saya membayangkan ini menghapus salah satu duplikat secara sewenang-wenang jadi pastikan tidak ada data yang berbeda antara setiap baris yang mungkin berguna untuk diketahui atau disimpan.
Joshua Pinter
1 untuk jawaban bahkan setelah terlambat 2 tahun. Saya tidak sengaja menghapus kunci komposit dan ini adalah penyelamat. Terima kasih
ivcode
Saya telah mencoba beberapa teknik pencari duplikasi dan tidak ada yang sesederhana dan secepat ini. Terima kasih telah membagikan metode ini.
Kristjan O.
8

Anda dapat menemukan duplikat seperti ini ..

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1
Jason Punyon
sumber
4

Untuk menemukan duplikat:

select stone_id, upcharge_title from tablename group by stone_id, upcharge_title having count(*)>1

Untuk membatasi agar menghindari hal ini di masa mendatang, buat kunci unik gabungan pada dua bidang ini.

Ian Nelson
sumber
1
Terima kasih banyak, dapatkah Anda memberi tahu saya cara menghapus semua kecuali satu duplikat. Dan bagaimana cara menyiapkan kunci compisite di phpmyadmin. TERIMA KASIH!!!
JD Isaacks
3

Secara kebetulan, batasan unik komposit di atas tabel akan mencegah hal ini terjadi sejak awal.

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(Ini adalah T-SQL yang valid. Tidak yakin tentang MySQL.)

P Ayah
sumber
1
Saya pikir itu berhasil tetapi tidak akan membiarkan saya melakukannya sampai saya menghapus duplikatnya terlebih dahulu. Terima kasih.
JD Isaacks
1

posting SO ini membantu saya, tetapi saya juga ingin tahu cara menghapus dan menyimpan salah satu baris ... berikut adalah solusi PHP untuk menghapus baris duplikat dan menyimpannya (dalam kasus saya hanya ada 2 kolom dan itu ada di fungsi untuk menghapus asosiasi kategori duplikat)

$dupes = $db->query('select *, count(*) as NUM_DUPES from PRODUCT_CATEGORY_PRODUCT group by fkPRODUCT_CATEGORY_ID, fkPRODUCT_ID having count(*) > 1');
if (!is_array($dupes))
    return true;
foreach ($dupes as $dupe) {
    $db->query('delete from PRODUCT_CATEGORY_PRODUCT where fkPRODUCT_ID = ' . $dupe['fkPRODUCT_ID'] . ' and fkPRODUCT_CATEGORY_ID = ' . $dupe['fkPRODUCT_CATEGORY_ID'] . ' limit ' . ($dupe['NUM_DUPES'] - 1);
}

(batas NUM_DUPES - 1) adalah yang mempertahankan satu baris ...

Terima kasih semuanya

groovenektar
sumber
3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)akan menghapus baris duplikat dan hanya menyisakan satu pasangan unik.
dev-null-dweller