1 değil 2 sütunda kopyalar nasıl bulunur


107

Beni ilgilendiren iki sütun içeren bir MySQL veritabanı tablom var. Tek tek her birinin kopyası olabilir, ancak hiçbir zaman aynı değere sahip İKİSİNİN HER İKİSİNİN kopyasına sahip olmamalıdır.

stone_idher upshargebaşlık için farklı ve tersi olduğu sürece kopyalar olabilir . Ancak örneğin stone_id= 412 ve upcharge_title= "safir" kombinasyonunun yalnızca bir kez olması gerektiğini söyleyin .

Tamamdır:

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

Bu TAMAM DEĞİL:

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

Her iki alanda da kopyaları bulacak bir sorgu var mı? Ve eğer mümkünse, veri tabanımı buna izin vermeyecek şekilde ayarlamanın bir yolu var mı?

MySQL 4.1.22 sürümünü kullanıyorum

Yanıtlar:


192

İki alan arasında bir bileşik anahtar ayarlamalısınız. Bu, her satır için benzersiz bir stone_id ve upcharge_title gerektirecektir.

Mevcut kopyaları bulmak için şunu deneyin:

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

Teşekkürler, bu onları seçiyor. Yinelenenleri nasıl sileceğimi söyler misiniz (ama elbette 1 kopya bırakın) TEŞEKKÜR EDERİM !!
JD Isaacks

2
Bunun bir yolu, tüm farklı verileri alıp tabloyu yeniden oluşturmak olabilir.
Miyagi Coder

1
@John Isaacks: Bunları ayırt edebileceğiniz başka alanlar yoksa (yani tüm alanlar yineleniyorsa), her iki satırı da silmeniz ve birini yeniden oluşturmanız gerekir. Bunun bir yolu, kopyaları tablonun bir kopyasına kopyalamak, bunları orijinalden silmek ve kopyadan farklı satırları yeniden eklemek olabilir.
P Baba

Bu postgres 8.1'de çalışmıyor, birisi bana yardım edebilir mi?
Lennon

çok teşekkürler, maddeye göre gruplandırdığınız sıra mı?
Andrew

35

Yinelenenleri kaldıran ve yapmak istediğiniz gibi görünen benzersiz kayıtları zorlayan bir "ALTER IGNORE" kullanarak benzersiz bir dizin eklemeyi yararlı buldum. Dolayısıyla sözdizimi şöyle olacaktır:

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

Bu, benzersiz kısıtlamayı etkili bir şekilde ekler, yani hiçbir zaman yinelenen kayıtlara sahip olmayacaksınız ve IGNORE, mevcut kopyaları siler.

ALTER IGNORE hakkında daha fazla bilgiyi buradan okuyabilirsiniz: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

Güncelleme: @Inquisitive tarafından bunun MySql> 5.5 sürümlerinde başarısız olabileceği konusunda bilgilendirildim:

MySQL> 5.5 ve InnoDB tablosunda ve InnoDB hızlı dizin oluşturma özelliği nedeniyle Percona'da başarısız olur [ http://bugs.mysql.com/bug.php?id=40344] . Bu durumda önce çalıştırın set session old_alter_table=1ve ardından yukarıdaki komut düzgün çalışacaktır.

Güncelleme - ALTER IGNORE5.7'de Kaldırıldı

Gönderen docs

MySQL 5.6.17'den itibaren, IGNORE yan tümcesi kullanımdan kaldırılmıştır ve kullanımı bir uyarı oluşturur. IGNORE, MySQL 5.7'de kaldırılmıştır.

MySQL geliştiricilerinden biri iki alternatif sunar :

  • Benzersiz alanlara göre gruplayın ve yukarıda görüldüğü gibi silin
  • Yeni bir tablo oluşturun, benzersiz bir dizin ekleyin INSERT IGNORE, örn:
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;

Ancak tablonuzun büyüklüğüne bağlı olarak bu pratik olmayabilir


1
Doğru, ama en azından bir dahaki sefere bilirsin. Aynı sorunu
yaşadım

Sadece 3 yıl geç olduğu için alay ediyordum. Paylaştığınıza gerçekten sevindim. Dolayısıyla artı 1.
JD Isaacks

Bunun kopyalardan birini keyfi olarak kaldırdığını düşünüyorum, bu nedenle her satır arasında bilinmesi veya saklanması yararlı olabilecek farklı veriler olmadığından emin olun.
Joshua Pinter

2 yıl geç kaldıktan sonra bile cevap için +1. Yanlışlıkla bir bileşik anahtarı sildim ve bu bir hayat kurtarıcıydı. Teşekkür ederim
ivcode

Birkaç kopya bulma tekniğini denedim ve hiçbiri bu kadar basit ve hızlı değildi. Bu yöntemi paylaştığınız için teşekkür ederiz.
Kristjan O.

8

Bunun gibi kopyaları bulabilirsiniz ..

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1

4

Kopyaları bulmak için:

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

Gelecekte bundan kaçınmak için sınırlamak için, bu iki alanda bileşik benzersiz bir anahtar oluşturun.


1
Çok teşekkür ederim, lütfen yinelenenlerden biri hariç tümünü nasıl sileceğimi söyler misiniz? Ve phpmyadmin'de bir compisite anahtarı nasıl kurarım. TEŞEKKÜR EDERİM!!!
JD Isaacks

3

Bu arada, tablodaki benzersiz bir bileşik kısıtlama, bunun ilk etapta gerçekleşmesini engelleyecektir.

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(Bu geçerli bir T-SQL'dir. MySQL hakkında emin değilim.)


1
Bunun işe yaradığını düşünüyorum, ancak önce kopyaları kaldırana kadar bunu yapmama izin vermeyecek. Teşekkürler.
JD Isaacks

1

Bu SO gönderisi bana yardımcı oldu, ancak ben de satırlardan birini nasıl silip saklayacağımı bilmek istedim ... işte yinelenen satırları silmek ve birini saklamak için bir PHP çözümü (benim durumumda sadece 2 sütun vardı ve bir yinelenen kategori ilişkilendirmelerini temizleme işlevi)

$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);
}

(NUM_DUPES - 1 sınırı) tek satırı koruyan şeydir ...

hepinize teşekkürler


3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)yalnızca bir benzersiz çift bırakarak yinelenen satırları kaldırır.
dev-null-dweller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.