MySQL tablosundaki kopyalar nasıl silinir?


158

DELETEBir MySQLtabloda belirtilen sid için yinelenen satırları gerekir .

Bunu bir SQL sorgusu ile nasıl yapabilirim?

DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"

Böyle bir şey, ama nasıl yapılacağını bilmiyorum.


Sadece bir kez mi yapmanız gerekiyor yoksa sürekli mi yapmanız gerekiyor?
Billy ONeal

Yinelenen kayıtlara sahip kayıtların tümü aynı verilere sahip mi, yoksa kalan alanlar birbirinden farklı mı? İlk seçeneğiniz varsa, tüm kayıtları silebilirsiniz, diğeri ise ikinci seçeneğiniz varsa, hangi kaydı saklamak istediğinizi nasıl belirliyorsunuz?
rael_kid

@Lex İlk seçenek. @Billy her zaman yapmam gerek.
Ali Demirci


1
Burada MySQL'in çeşitli versiyonlarında değişen birçok şey var. Buradaki çözümlerden herhangi birinin yolunu atmadan önce MySQL sürümünüzü dikkatlice kontrol edin.
delatbabel

Yanıtlar:


215

bu, yeni bir tablo oluşturmadan kopyaları kaldırır

ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)

not: sadece indeks hafızaya uyuyorsa iyi çalışır


26
Uyarı: bu en eski yinelenen kaydı tutacak ve daha yeni olanları silecektir. En yenisini korumak istiyorsanız bunu yapamazsınız ALTER IGNORE.
Haralan Dobrev

9
InnoDB ile çalışmıyor gibi görünüyor. ALTER TABLE foo ENGINE MyISAMEtrafta koştum , sonra motoru değiştirdim.
Martin

13
bu MySQL> 5.5'te başarısız olabilir, eğer öyleyse "set session old_alter_table = 1;" ve "oturumu ayarla old_alter_table = 0;" açıklamadan önce ve sonra
chillitom


2
@delatbabel Kullanımdan kaldırılmasının nedeni, bağlandığınız sayfada verilmiştir.
Barmar

133

employeeAşağıdaki sütunları içeren bir tablonuz olduğunu varsayalım :

employee (first_name, last_name, start_date)

Yinelenen bir first_namesütuna sahip satırları silmek için :

delete
from employee using employee,
    employee e1
where employee.id > e1.id
    and employee.first_name = e1.first_name  

1
Kalan kayıt, çoğaltma grubunda maksimum veya minimum kimliğe sahip olacak mı?
Donmuş Alev

Geriye kalan kayıt, silinecek koşulu karşılamayan tek kayıt olduğu için minimum kimliğe sahip olacak
Pablo Guerrero

1
employeeBir dizin eşleşmesi için kendisine katılma gibi görünüyor ve >bir dizin üzerinde bir denetim büyük tablolar için yavaş olacak. Daha iyi için olmaz SELECT MAX(ID) FROM t GROUP BY uniqueve daha sonra JOINtam bir maça IDkadar MAX(ID)?
ebyrob

1
Mükemmel cevap! Zamanımı kurtardım!
Nesar

56

Aşağıda yalnızca tek bir tane değil, tüm SID'ler için yinelenenleri kaldırın.

Sıcaklık tablosu ile

CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;

DROP TABLE table;
RENAME TABLE table_temp TO table;

temp_tableYeni oluşturulduğundan beri dizini yoktur. Yinelemeleri kaldırdıktan sonra bunları yeniden oluşturmanız gerekir. Tabloda hangi dizinlerin bulunduğunu kontrol edebilirsinizSHOW INDEXES IN table

Temp tablosu olmadan:

DELETE FROM `table` WHERE id IN (
  SELECT all_duplicates.id FROM (
    SELECT id FROM `table` WHERE (`title`, `SID`) IN (
      SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
    )
  ) AS all_duplicates 
  LEFT JOIN (
    SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
  ) AS grouped_duplicates 
  ON all_duplicates.id = grouped_duplicates.id 
  WHERE grouped_duplicates.id IS NULL
)

4
GROUP-ing, grupladığınız alanların her bir değer kombinasyonu için yalnızca bir sonuç satırı üretir. Böylece kopyalar kaldırılacak.
Kamil Szot

4
İlk yolu seviyorum, burada çok zarif! : B
AgelessEssence

1
@fiacre Yabancı anahtar denetimlerini geçici olarak devre dışı bırakabilirsiniz: stackoverflow.com/questions/15501673/… Diğer tabloların başvurduğu satırlardan bazılarının kaldırılması da riskli olabilir, ancak sorguyu değiştirerek hangi kayıtların tekilleştirilen tabloya alındığını denetleyebilirsiniz. SELECT * FROM table GROUP BY title, SID;Her şey ne yaptığınızı ne kadar iyi bildiğinize bağlıdır.
Kamil Szot

1
@ahnbizcad Geçici tablo kullanabilirsiniz, ancak daha sonra verileri geçici tablodan normal tabloya kopyalamanız gerekir. Gerçek tablo kullanıyorsanız, eskisini kopyalarla birlikte bırakıp yenisini, eskisinin adına çoğaltmadan yeniden adlandırabilirsiniz.
Kamil Szot

1
"Geçici tabloya olmadan" yöntemi olabilecek en iyi çözümdür ancak MySQL 5.7.5 değişti ONLY_FULL_GROUP_BY elleçleme dikkat geçerli: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html bu var SELECT id "yerine" SELECT ANY_VALUE (id) AS id "ile değiştirerek çalışma
delatbabel

53

MySQL yerinde yinelenen satırları silme, (Sıralamak için bir zaman damgası sütununuz olduğu varsayılarak)

Tabloyu oluşturun ve bazı satırlar ekleyin:

create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
    +------+----------+---------------------+
    | foo  | bar      | baz                 |
    +------+----------+---------------------+
    |    1 | skipper  | 2014-08-25 14:21:54 |
    |    1 | skipper  | 2014-08-25 14:21:59 |
    |    3 | kowalski | 2014-08-25 14:22:09 |
    |    3 | kowalski | 2014-08-25 14:22:13 |
    |    3 | kowalski | 2014-08-25 14:22:15 |
    |    4 | rico     | 2014-08-25 14:22:22 |
    +------+----------+---------------------+
6 rows in set (0.00 sec)

Kopyaları kaldırın:

delete a
    from penguins a
    left join(
    select max(baz) maxtimestamp, foo, bar
    from penguins
    group by foo, bar) b
    on a.baz = maxtimestamp and
    a.foo = b.foo and
    a.bar = b.bar
    where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo  | bar      | baz                 |
+------+----------+---------------------+
|    1 | skipper  | 2014-08-25 14:21:59 |
|    3 | kowalski | 2014-08-25 14:22:15 |
|    4 | rico     | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)

İşiniz bitti, yinelenen satırlar kaldırıldı, sonuncusu zaman damgası olarak tutuldu.

Zaman damgası veya benzersiz sütun olmayanlar için.

timestampSıralamak için bir veya benzersiz bir dizin sütununuz yok mu? Sen dejenerasyon halinde yaşıyorsun. Yinelenen satırları silmek için ek adımlar atmanız gerekir.

penguenler tablosunu oluşturun ve bazı satırlar ekleyin

create table penguins(foo int, bar varchar(15)); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(4, 'rico'); 
select * from penguins; 
    # +------+----------+ 
    # | foo  | bar      | 
    # +------+----------+ 
    # |    1 | skipper  | 
    # |    1 | skipper  | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    4 | rico     | 
    # +------+----------+ 

ilk tablonun bir klonunu yapın ve içine kopyalayın.

drop table if exists penguins_copy; 
create table penguins_copy as ( SELECT foo, bar FROM penguins );  

#add an autoincrementing primary key: 
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first; 

select * from penguins_copy; 
    # +-----+------+----------+ 
    # | moo | foo  | bar      | 
    # +-----+------+----------+ 
    # |   1 |    1 | skipper  | 
    # |   2 |    1 | skipper  | 
    # |   3 |    3 | kowalski | 
    # |   4 |    3 | kowalski | 
    # |   5 |    3 | kowalski | 
    # |   6 |    4 | rico     | 
    # +-----+------+----------+ 

Maksimum toplam, yeni moo endeksi üzerinde çalışır:

delete a from penguins_copy a left join( 
    select max(moo) myindex, foo, bar 
    from penguins_copy 
    group by foo, bar) b 
    on a.moo = b.myindex and 
    a.foo = b.foo and 
    a.bar = b.bar 
    where b.myindex IS NULL; 

#drop the extra column on the copied table 
alter table penguins_copy drop moo; 
select * from penguins_copy; 

#drop the first table and put the copy table back: 
drop table penguins; 
create table penguins select * from penguins_copy; 

gözlemle ve temizle

drop table penguins_copy; 
select * from penguins;
+------+----------+ 
| foo  | bar      | 
+------+----------+ 
|    1 | skipper  | 
|    3 | kowalski | 
|    4 | rico     | 
+------+----------+ 
    Elapsed: 1458.359 milliseconds 

Bu büyük SQL silme ifadesi ne yapıyor?

'A' takma adı olan tablo penguenleri, 'b' takma adı denilen tablo penguenlerinin bir alt kümesinde birleştirilir. Alt küme olan sağ b 'b' tablosu, foo ve bar sütunlarına göre gruplandırılmış maksimum zaman damgasını [veya maks. Moo] bulur. Bu sol taraftaki 'a' tablosuyla eşleştirilir. (foo, bar, baz) soldaki tablodaki her satıra sahiptir. Sağ alt küme 'b', yalnızca maks. IS'de olanla eşleşen bir (maxtimestamp, foo, bar) vardır.

Bu max olmayan her satırın NULL değerinde maxtimestamp değeri vardır. Bu NULL satırları filtreleyin ve foo ve bar ile gruplandırılmış en son zaman damgası baz olmayan tüm satırların bir kümesine sahipsiniz. Bunları silin.

Bunu çalıştırmadan önce tablonun bir yedeğini alın.

Bu sorunun bu tabloda bir daha oluşmasını önleyin:

Eğer bu işe yaradı ve "yinelenen satır" yangın söndürüldü. Harika. Şimdi, daha fazla yinelemenin eklenmesini önlemek için tablonuzda yeni bir bileşik benzersiz anahtar tanımlayın (bu iki sütunda).

İyi bir bağışıklık sistemi gibi, kötü sıraların yerleştirme sırasında masaya girmesine bile izin verilmemelidir. Daha sonra tüm bu programlarda yinelenen kayıtlar protestolarını yayınlayacak ve düzelttiğinizde bu sorun bir daha ortaya çıkmayacak.


6
sadece Madagaskar referansı için puan verin!
Michael Wiggins

1
Bu harika bir cevap ve harika öneriler olduğu için puanlandı, teşekkürler Eric orada diğer cevaplardan daha iyi çalıştı.
johan

4
Not: Tablonuzda otomatik bir artış IDsütunu varsa, ONyan tümce yalnızca IDsütunla eşleşmelidir , başka bir şey yoktur.
ebyrob

1
Ayrıntılı açıklamayı seviyorum ama ... Doğru anlarsam, bu cevap kayıtları ayırt etmek için zaman damgasını kullanır. Bu anlamda kayıtlar kopya değil. Kayıtları ayırt etmek için zaman damganız yoksa yani tüm sütunlar 2 veya daha fazla kayıt için aynı ise ne olur?
Rsc Rsc

1
@RscRsc Maksimum toplamı uygulamak için bir zaman damgası sütununuz veya benzersiz bir dizininiz yoksa, tabloyu çoğaltmanız, benzersiz bir dizin eklemeniz, delete ifadesini uygulamanız ve ardından kopyalanan tabloyu orijinal ile değiştirmeniz gerekir. . Cevabı bu talimatları yansıtacak şekilde değiştirdim.
Eric Leschinski

16

Bu konuya kendim girdikten sonra, büyük bir veritabanında, diğer cevapların performansından tamamen etkilenmedim. Yalnızca en son yinelenen satırı tutmak ve geri kalanını silmek istiyorum.

Tek sorgu ifadesinde, geçici tablo olmadan, bu benim için en iyi sonucu verdi,

DELETE e.*
FROM employee e
WHERE id IN
 (SELECT id
   FROM (SELECT MIN(id) as id
          FROM employee e2
          GROUP BY first_name, last_name
          HAVING COUNT(*) > 1) x);

Tek uyarı, sorguyu birden çok kez çalıştırmak zorunda olduğumdur, ancak bununla birlikte, benim için diğer seçeneklerden daha iyi çalıştığını gördüm.


1
Pragmatik çözüm! Benim için - yaklaşık 20s 2m + satır innodb tablo için çalıştı. Birkaç kez kullandığımda ve çok sayıda kopyaya sahip birkaç suçluya düştüğümde, işi manuel olarak bitirdim.
Troy Wray

1
Benim için bir taramada çalıştı, harika!
Murwa

Herhangi bir sütun için kopyalar 2
kattan

@PayteR, "Tek uyarı, sorguyu birden çok kez çalıştırmam gerektiğidir"
seaders

13

Bu her zaman benim için çalışıyor gibi görünüyor:

CREATE TABLE NoDupeTable LIKE DupeTable; 
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;

Bu, çiftlerin her birinde ve dupe olmayan kayıtların geri kalanında en düşük kimliği tutar.

Ben de dupe sorunu kaldırıldıktan sonra artık oluşmaması için aşağıdakileri yaptım:

CREATE TABLE NoDupeTable LIKE DupeTable; 
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;

Başka bir deyişle, ilk tablonun bir kopyasını oluşturuyorum, kopyalarını istemediğim alanlara benzersiz bir dizin ekliyorum ve sonra ilk kez eklemeye çalıştığında Insert IGNOREnormal olarak başarısız olmama avantajına sahip bir tane yapıyorum Insertiki alana dayalı yinelenen bir kayıttır ve bu tür kayıtları yoksayar.

İleri hareket ettirildiğinde, bu iki alana dayalı yinelenen kayıtlar oluşturmak imkansız hale gelir.


1
Bir ihtiyaç olmaz ORDER BYiçinde SELECTaslında onu üzerinden yapar rekor emin olmak için NoDupeTable?
ebyrob

@ebyrob Aksi belirtilmedikçe, diğer kriterlerin yokluğunda en düşük kimliği seçeceğine inanıyorum. Tabii ki ORDER by ID Ascincitemedi, buna rağmen cevabımı düzenleyeceğim.
user3649739

@ebyrob Üzgünüm kötü. Sıralama ölçütü bu seçimde bilgim için çalışmaz. Seçimin sonundaki bir Sipariş, yalnızca her çiftte bulunan en düşük kimlik tarafından bulunan kopyaları sıralar. Alternatif olarak bir Select Max(ID)ve daha sonra Order by Max(ID)da yapabilirsiniz, ancak tüm yapmanız gereken ekin sırasını tersine çevirmektir. En yüksek kimliği kapmak için daha karmaşık bir seçim katılmak gibi inanıyorum, yukarıdaki sipariş ne olursa olsun, daha düşük ID alan değerleri kapmak olacaktır.
user3649739

Aslında, emirle ne düşündüğümden emin değilim. Kesinlikle isterdim MAX(ID)ya MIN(ID)ve yerine sütun adları *içinde SELECT FROM DupeTableaksi takdirde sadece birini alırsınız olsa ID'rastgele s. Aslında, birçok SQL ve hatta MySQL katı, GROUP BYmaddede belirtilmeyen her bir sütunda bir toplama işlevinin çağrılmasını gerektirir .
ebyrob

@ebyrob Max (ID) Min (ID) testinde Max veya Mind kaydının kimliğini döndürmek dışında hiçbir şey yapmayın. Her durumda aynı kayıtları tutar. Alanlar ID,First,Last,Notesve kayıtlar ile iki kayıt vardı 1,Bob,Smith,NULLve 2,Bob,Smith,Arrearssonra bir yapmak SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastfarklı bir kimlik dışında, aynı kaydı, 1 dönecekti. Maks (ID) dönecek 2,Bob,Smith,NULLve Min (ID) dönecektir 1,Bob,Smith,NULL. Notlarda `` Arrears '' ile ikinci rekoru almak için inanıyorum bir katılma gerektirir.
user3649739

7

Tüm tablolar için aşağıdakiler çalışır

CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;

6

İşte basit bir cevap:

delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated  
    from target_table GROUP BY field_being_repeated) b 
    on a.field_being_repeated = b.field_being_repeated
      and a.id_field = b.id_field
    where b.id_field is null;

Küçük bir hata dışında iyi bir cevapand a.id_field = b.id
Vikrant Goel

LEFT JOINİçin bsadece karşılaştırma ihtiyacı b.id= a.id_fieldvarsayarak field_idbenzersiz otomatik artış kimliğidir. bu a.field_being_repeated = b.field_being_repeatedda yabancı. (ayrıca b.id_fieldbu sorguda mevcut değil b.id.
ebyrob

6

Bu çalışma benim için eski kayıtları kaldırmak için:

delete from table where id in 
(select min(e.id)
    from (select * from table) e 
    group by column1, column2
    having count(*) > 1
); 

En yeni kayıtları kaldırmak için min (e.id) değerini max (e.id) olarak değiştirebilirsiniz.


5
delete p from 
product p
inner join (
    select max(id) as id, url from product 
    group by url 
    having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;

1
Yukarıdaki çözümlerden çok daha başarılı bir çözüm buldum
Christian Butzke

5

Ben Werner çözüm bulmak yukarıdaki o birincil anahtar varlığının bağımsız çalışır tablolarla karışıklık değil, geleceğe yönelik düz sql kullanan çok anlaşılır olduğu için en uygun olması.

Yorumumda belirttiğim gibi, bu çözüm doğru bir şekilde açıklanmadı. Yani bu benim.

1) yeni bir boole sütunu ekleyin

alter table mytable add tokeep boolean;

2) çoğaltılan sütunlara VE yeni sütuna bir kısıtlama ekleyin

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

3) boole sütununu true olarak ayarlayın. Bu, yeni kısıtlama nedeniyle yalnızca çoğaltılan satırlardan birinde başarılı olacaktır

update ignore mytable set tokeep = true;

4) tokeep olarak işaretlenmemiş satırları sil

delete from mytable where tokeep is null;

5) Eklenen Sütunu Bırakın

alter table mytable drop tokeep;

Gelecekte yeni kopyaların önlenmesi için eklediğiniz kısıtlamayı korumanızı öneririz.


4

Bu yordam, tablodaki tüm kopyaları (katlar dahil) kaldırarak son kopyayı tutar. Bu, her gruptaki son kaydı almanın bir uzantısıdır

Umarım bu birisi için yararlıdır.

DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));

INSERT INTO UniqueIDs
    (SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
    (T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields 
    AND T1.ID < T2.ID)
    WHERE T2.ID IS NULL);

DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);

4

Başka bir kolay yol ... UPDATE IGNORE kullanarak:

U, bir veya daha fazla sütun (tür dizini) üzerinde bir dizin kullanmak zorunda. Yeni bir geçici başvuru sütunu oluşturun (dizinin bir parçası değil). Bu sütunda, benzersizleri yoksay yan tümcesi ile güncelleyerek işaretlersiniz. Adım adım:

Benzersizleri işaretlemek için geçici bir referans sütunu ekleyin:

ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;

=> bu tablonuza bir sütun ekleyecektir.

Tabloyu güncelleyin, her şeyi benzersiz olarak işaretlemeyi deneyin, ancak yinelenen anahtar sorunu nedeniyle olası hataları yok sayın (kayıtlar atlanacaktır):

UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;

=> yinelenen kayıtlarınızın benzersiz olarak işaretlenmeyeceğini göreceksiniz = 'Evet', diğer bir deyişle her yinelenen kayıt kümesinden yalnızca biri benzersiz olarak işaretlenecek.

Benzersiz olmayan her şeyi silin:

DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';

=> Bu tüm yinelenen kayıtları silecektir.

Sütunu bırak ...

ALTER TABLE `yourtable` DROP `unique`;

Bunun en iyi çözüm olduğunu düşünüyorum çünkü tablolarla uğraşmıyor ve basit basit sql kullanıyor. Tek bir şey açıklığa kavuşturulmalıdır: uniqueSütun, şu anda çoğaltılan sütunlarla birlikte benzersiz bir kısıtlamaya eklenmelidir ZORUNLUDUR, aksi takdirde her şey çalışmaz çünkü SET unique= 'Yes' asla başarısız olmaz.
xtian

Ayrıca uniquebir mysql anahtar kelime olduğunu unutmayın. Bu yüzden geri çekilmeleri (zaten doğru şekilde gösterildiği gibi) olması gerekir. Sütun için başka bir kelime kullanmak daha uygun olabilir.
Torsten

2

MySQL tablolarındaki kopyaları silmek, genellikle belirli gereksinimlerle birlikte gelen yaygın bir sorundur. Herkes ilgileniyorsa, burada ( MySQL'de yinelenen satırları kaldırın ) MySQL yinelemelerini güvenilir ve hızlı bir şekilde silmek için geçici bir tablonun nasıl kullanılacağını açıklarım, ayrıca büyük veri kaynaklarını işlemek için de geçerlidir (farklı kullanım durumları için örneklerle).

Ali , senin durumunda, böyle bir şey çalıştırabilirsin:

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;

-- add a unique constraint    
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);

-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;

-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;

0
delete from `table` where `table`.`SID` in 
    (
    select t.SID from table t join table t1 on t.title = t1.title  where t.SID > t1.SID
)

Bu, MySQL'in bazı yapılandırmalarında ve sürümlerinde SQL Hatası (1093) oluşturur.
ebyrob

0

Love @ eric'in cevabı ama gerçekten büyük bir masanız varsa işe yaramıyor ( The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okayçalıştırmaya çalıştığımda alıyorum ). Bu yüzden sadece yinelenen satırları dikkate almak için birleştirme sorgusu sınırlı ve ben ile sona erdi:

DELETE a FROM penguins a
    LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
        FROM penguins
        GROUP BY deviceId HAVING num > 1) b
        ON a.baz != b.keepBaz
        AND a.foo = b.foo
    WHERE b.foo IS NOT NULL

Bu durumda WHERE deyimi, MySQL'in yinelenmeyen herhangi bir satırı yoksaymasına izin verir ve yinelenen öğenin ilk örneği olup olmadığını da göz ardı eder, böylece yalnızca sonraki yinelenmeler yok sayılır. Değişim MIN(baz)için MAX(baz)yerine ilk son örneğini tutmak için.


0

Bu büyük tablolar için geçerlidir:

 CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;

 DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;

Olarak yapılan en eski değişikliği silmek max(id)içinmin(id)


0

Bu, sütunu column_namebirincil anahtara dönüştürür ve bu arada tüm hataları yok sayar. Böylece yinelenen değeri olan satırları siler column_name.

ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);

Önceki cevabın yorumlarında belirtildiği gibi, bu artık 5.7'de çalışmıyor.
Barmar

0

Bu temelde tablo kopyalayıp boşaltıp sonra sadece farklı değerleri geri koyarak işe yarayacağını düşünüyorum ama lütfen büyük miktarda veri üzerinde yapmadan önce iki kez kontrol edin.

Tablonuzun bir karbon kopyasını oluşturur

oldtablename gibi temp_table tablosu oluşturun; eski_adı adından temp_table select * yazın;

Orijinal tablonuzu boşaltır

Oldtablename'den DELETE *;

Kopyalanan tablodaki tüm farklı değerleri orijinal tablonuza geri kopyalar

Temp_table grubundan ad, soyad, dob ile eski tablo adı SELECT * ekle

Geçici tablonuzu siler.

Tabloyu Bırak

Farklı tutmak istediğiniz aLL alanlarına göre gruplandırmanız gerekir.


0
DELETE T2
FROM   table_name T1
JOIN   same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)

isteğiniz işe yaramıyor, lütfen geliştirebilir misiniz?
Samir Guiderk

0

işte genellikle kopyaları nasıl ortadan kaldırırım

  1. geçici bir sütun ekleyin, istediğinizi adlandırın (etkin olarak anlatacağım)
  2. yinelenmemesi gerektiğini düşündüğünüz alanlara göre gruplandırın ve etkin olduklarını 1 olarak ayarlayın, gruba göre gruplandırma, bu sütunlar için yinelenen değerlerden yalnızca birini seçer (yinelenenleri seçmez)
  3. aktif sıfıra sahip olanları sil
  4. bırakma sütunu etkin
  5. isteğe bağlı olarak (amaçlarınıza uygunsa), bu sütunların tekrar kopyası olmaması için benzersiz bir dizin ekleyin

-2

Sadece "temizlenmiş" listesi seçmek için bir DISTINCT yan tümcesi kullanabilirsiniz (ve burada bunu nasıl üzerinde çok kolay bir örneğidir).


Bu soruya nasıl cevap veriyor? DISTINCTSizi kullanmak , ilk etapta kopyalarınızla ilgili herhangi bir bilgiyi kaybeder. Bunu kullanarak kopyaları silmenin bir yolunu gösterebilir misiniz?
luk2302

-3

Onları sayarsanız ve ardından silme sorgunuza yalnızca bir tane bırakarak bir sınır ekleyebilir misiniz?

Örneğin, iki veya daha fazlasınız varsa, sorgunuzu şu şekilde yazın:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

Yinelenen verileri tablonuzdan kaldırırken yalnızca birkaç temel adım vardır:

  • Masanızı yedekleyin!
  • Yinelenen satırları bulma
  • Yinelenen satırları kaldırma

İşte tam eğitici: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473


Sadece benzersiz kimlik farklıysa çalışır. Eğer sadece benzersiz id farklı ise de bu işe yarar mı?
Andrew

Varsayılan olarak, burada açıklanan yöntem MySQL sürümleri> 5.7.5 için çalışmaz. Bunun nedeni ONLY_FULL_GROUP_BY'nin kullanımıdır. Buraya bakın: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
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.