MySQL'deki yinelenen satırları kaldırma


375

Aşağıdaki alanları içeren bir tablo var:

id (Unique)
url (Unique)
title
company
site_id

Şimdi, aynı satırları kaldırmam gerekiyor title, company and site_id. Bunu yapmanın bir yolu bir script ( PHP) ile birlikte aşağıdaki SQL kullanmak olacaktır :

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

Bu sorguyu çalıştırdıktan sonra, sunucu tarafı komut dosyası kullanarak yinelenenleri kaldırabilirim.

Ancak, bunun sadece SQL sorgusu kullanılarak yapılabileceğini bilmek istiyorum.


1
Hızlı soru: her zaman yinelenen (başlık, şirket, site_kimliği) olmasını istemiyor musunuz? Eğer öyleyse, başlık, şirket ve site_id benzersiz olması için veritabanında bir kısıtlama ayarlamak. Bu, bir temizleme işlemine ihtiyacınız olmayacağı anlamına gelir. Ve sadece tek bir SQL satırı alır.
J. Polfer

1
Lütfen stackoverflow bu linke bakın . Benim için bir cazibe olarak çalıştı.

Bu çözümü önerebilirim (başka bir konuya gönderildi): stackoverflow.com/a/4685232/195835
Simon East

Yanıtlar:


607

Bunu yapmanın gerçekten kolay bir yolu UNIQUE, 3 sütuna bir dizin eklemektir . İfadeyi yazarken ALTER, IGNOREanahtar kelimeyi ekleyin . Şöyle ki:

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

Bu, tüm yinelenen satırları bırakacaktır. Ek bir fayda olarak, INSERTskopya olan gelecek hata verecektir. Her zaman olduğu gibi, böyle bir şey çalıştırmadan önce yedek almak isteyebilirsiniz ...


8
İlginç , ancak IGNORE maddesinin bu kopyaları kaldırmak için yaptığı varsayımlar, ihtiyaçları karşılamayabilecek bir endişe kaynağıdır. Hatalı değerler kabul edilebilir en yakın eşleşme sesine kısaltıldı mı?
OMG Ponies

75
Sadece kayıt için InnoDB kullanıyorsanız, o zaman onunla bir sorun olabilir, InnoDB veritabanlarıyla ALTER IGNORE TABLE kullanma hakkında bilinen bir hata var.
DarkMantis


42
InnoDB tabloları için önce aşağıdaki sorguyu yürütün:set session old_alter_table=1;
shock_one


180

Sütun özelliklerini değiştirmek istemiyorsanız, aşağıdaki sorguyu kullanabilirsiniz.

Benzersiz kimlikleri (örneğin auto_incrementsütunlar) olan bir sütununuz olduğundan, kopyaları kaldırmak için kullanabilirsiniz:

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

MySQL'de, NULL güvenli eşit operatör (diğer adıyla "uzay gemisi operatörü" ) ile daha da basitleştirebilirsiniz :

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`;

3
Bu çözüm düzgün çalışmıyor, bazı yinelenen kayıtlar yapmaya çalıştım ve (20 satır etkilenen) gibi bir şey yapar, ancak tekrar çalıştırırsanız size (4 satır etkilenen) gösterir ve ulaşana kadar (0 satır etkilenir) Bu biraz şüpheli ve benim için en iyi olan şey işte, neredeyse aynı ama bir seferde çalışıyor, çözümü düzenledim
Nassim

1
@Nassim: Bu cevaptan farklı bir şey yapmalısın çünkü benim için mükemmel çalışıyor (MySQL'de).
Lawrence Dol

3
Benim gibi kafası karışmış herkes için NULL karşılaştırma terimleri gereklidir, çünkü NULL MySQL'de NULL değerine eşit değildir. İlgili sütunların NULL olmadığı garanti edilirse, bu şartları dışarıda bırakabilirsiniz.
Ian

3
Evet, kabul edilen cevap artık geçerli değil, çünkü MYSQL 5.7 bu yüzden evrensel olduğu için geçici olarak kabul edilmiş cevap olmalı ve geçici tablo oluşturma gerektirmez.
that-ben

1
Belirli bir kaydın ÇOK YAVAŞ olması durumunda (örneğin 100, 1'e indirilecek) ve bu koşulu olan birçok kayıt. Bunun yerine stackoverflow.com/a/4685232/199364 önerilir . IMHO, DAİMA bağlantılı yaklaşımı kullanır; doğal olarak daha hızlı bir tekniktir.
ToolmakerSteve

78

MySQL, sildiğiniz tabloya gönderme konusunda kısıtlamalara sahiptir. Bunun gibi geçici bir tablo ile çalışabilirsiniz:

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

Kostanos'un yorumlardaki önerisinden:
Yukarıdaki tek yavaş sorgu, çok büyük bir veritabanına sahip olduğunuz durumlar için DELETE'dir . Bu sorgu daha hızlı olabilir:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

3
@andomar, nerede yan tümcesindeki alanlardan birinin null içermesi dışında bu iyi çalışır. Örnek: sqlfiddle.com/#!2/983f3/1
bir kodlayıcı

1
Insert SQL pahalı mı? Merak ediyorum çünkü MySQL veritabanımda zaman aşımına uğradı.
Cassio

4
Buradaki tek yavaş sorgu, büyük veritabanınız olması durumunda SİL'i siler. Bu sorgu daha hızlı olabilir:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos

@Kostanos Sadece değil DELETE, aynı zamanda INSERTgeçici masaya da gitmek uzun zaman aldı. Yani tmp tablosu için bir dizin create index tmpTable_id_index on tmpTable (id)en azından benim için çok yardımcı olabilir .
Jiezhi.G

1
Tablolarınız büyükse, aşağıdakileri içeren bir dizin eklemeye değer: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke

44

İfadem IGNOREbenim durumumdaki gibi çalışmazsa, aşağıdaki ifadeyi kullanabilirsiniz:

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;

1
yabancı anahtar kısıtlaması ile innoDB ayarınız varsa harika çalışıyor.
magdmartin

@magdmartin, ancak yabancı kısıtlamalar tablonun silinmesini engellemiyor mu?
Basilevs

1
IGNORE ifadesi benim için işe yaramadı ve bu 5 milyon kayıt çıkarmada çok işe yaradı. Şerefe.
Mauvis Ledford

32

MySQL tablolarındaki kopyaları silmek yaygın bir sorundur, bu genellikle bu kopyaları önceden önlemek için eksik bir kısıtlamanın sonucudur. Ancak bu ortak sorun genellikle belirli yaklaşımlar gerektirir ... belirli yaklaşımlar gerektirir. Yaklaşım, örneğin, verilerin boyutuna, saklanması gereken yinelenen girişe (genellikle ilk veya sonuncusu), saklanacak dizinlerin olup olmamasına veya herhangi bir ek gerçekleştirmek isteyip istemediğimize bağlı olarak farklı olmalıdır. yinelenen veriler üzerinde eylem.

MySQL'in kendisinde de bir tablo UPDATE gerçekleştirirken aynı tabloyu bir FROM nedeninde referans gösterememe gibi bazı özellikler vardır (MySQL hatası # 1093'ü yükseltir). Bu sınırlama, geçici tablo içeren bir iç sorgu kullanılarak (yukarıdaki bazı yaklaşımlarda önerildiği gibi) aşılabilir. Ancak bu iç sorgu, büyük veri kaynaklarıyla uğraşırken özellikle iyi performans göstermez.

Bununla birlikte, hem etkili hem de güvenilir olan ve farklı ihtiyaçlara kolayca uyarlanabilen kopyaları kaldırmak için daha iyi bir yaklaşım vardır.

Genel fikir, daha fazla yinelemeden kaçınmak için genellikle benzersiz bir kısıtlama ekleyerek yeni bir geçici tablo oluşturmak ve yinelemelere dikkat ederken eski tablonuzdaki verileri yenisine yerleştirmektir. Bu yaklaşım basit MySQL INSERT sorgularına dayanır, daha fazla kopyadan kaçınmak için yeni bir kısıtlama oluşturur ve kopyaları aramak için bir iç sorgu ve bellekte tutulması gereken geçici bir tablo kullanma ihtiyacını atlar (böylece büyük veri kaynaklarını da sığdırır).

Bu şekilde elde edilebilir. Aşağıdaki sütunları içeren bir tablo çalışanımız var :

employee (id, first_name, last_name, start_date, ssn)

Yinelenen bir ssn sütunu içeren satırları silmek ve yalnızca ilk girdiyi saklamak için aşağıdaki işlem izlenebilir:

-- 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;

Teknik açıklama

  • Satır # 1 , çalışan tabloyla tamamen aynı yapıya sahip yeni bir tmp_eployee tablosu oluşturur
  • Satır 2, daha fazla yinelemeyi önlemek için yeni tmp_eployee tablosuna UNIQUE kısıtlaması ekler
  • 3. Satır, orijinal çalışan tablosunu kimliğe göre tarar ve yinelenen girişleri yok sayarken yeni tmp_eployee tablosuna yeni çalışan girişleri ekler
  • 4. satır tabloları yeniden adlandırır, böylece yeni çalışan tablosu tüm girişleri kopyalar olmadan tutar ve önceki verilerin yedek bir kopyası backup_employee tablosunda tutulur.

Bu yaklaşım kullanılarak, 1.6 M kayıt 200s daha az bir sürede 6K dönüştürüldü.

Chetan , bu işlemi izleyerek, tüm kopyalarınızı hızlı ve kolay bir şekilde kaldırabilir ve çalıştırarak UNIQUE kısıtlaması oluşturabilirsiniz:

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;

Elbette, bu süreç, kopyaları silerken farklı ihtiyaçlara uyarlamak için daha fazla değiştirilebilir. Aşağıda bazı örnekler verilmiştir.

✔ İlk girişi yerine son girişi tutma çeşidi

Bazen birincisi yerine en son yinelenen girişi tutmamız gerekir.

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;
  • 3. satırda, ORDER BY id DESC yan tümcesi, diğer kimliklerin önceliğe göre öncelik kazanmasını sağlar

✔ Kopyalarda bazı görevleri gerçekleştirmek için varyasyon, örneğin bulunan kopyaları saymak

Bazen bulunan yinelenen girişler üzerinde bazı işlemler yapmamız gerekir (yinelenenleri saymak gibi).

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;
  • 3. satırda, yeni bir sütun n_duplicates oluşturulur
  • Satır # 4, INUP ... IN DUPLICATE KEY UPDATE sorgusu, yinelenen bir dosya bulunduğunda ek bir güncelleştirme gerçekleştirmek için kullanılır (bu durumda, bir sayaç artar) INSERT INTO ... ON DUPLICATE KEY UPDATE sorgusu bulunan kopyalar için farklı türde güncellemeler gerçekleştirmek için kullanılır.

✔ Otomatik artan alan kimliğini yeniden oluşturma varyasyonu

Bazen otomatik artımlı bir alan kullanırız ve dizini olabildiğince küçük tutmak için yeni geçici tabloda otomatik artımlı alanı yeniden oluşturmak için kopyaların silinmesinden yararlanabiliriz.

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;
  • 3. satırda, tablodaki tüm alanları seçmek yerine, id motoru atlanır, böylece DB motoru otomatik olarak yeni bir alan oluşturur

✔ Diğer varyasyonlar

İstenen davranışa bağlı olarak başka birçok değişiklik de yapılabilir. Örnek olarak, aşağıdaki sorgularda ikinci bir geçici tablo kullanılacaktır, bunun yanında 1) birincisi yerine son girdiyi tutmak; ve 2) bulunan kopyalarda bir sayacın arttırılması; ayrıca 3) giriş verisini önceki verilerdeki gibi korurken otomatik artımlı alan kimliğini yeniden oluşturun.

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;

27

Başka bir çözüm daha var:

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 ...

4
Bu, 6 ay önce sunduğu @ rehriff'in cevabından ne farkı var?
Lawrence Dol

@LawrenceDol Sanırım biraz daha okunabilir ve aynı zamanda cevabının cevap verdiğim sırada aynı olmadığını düşünüyorum ve cevabının düzenlendiğini düşünüyorum.
Mostafa -T

1
hı. Kayıt sayısı fazla olmasa da benim için çok uzun sürüyor!
SuB

8

Çok sayıda kayıt içeren büyük bir tablonuz varsa, yukarıdaki çözümler işe yaramaz veya çok fazla zaman almaz. Sonra farklı bir çözümümüz var

-- 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;

6

SQLServer için bu sorgu snipet var ama küçük değişikliklerle diğer DBMS kullanılabilir düşünüyorum:

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

Bu sorgunun çoğaltılan satırların en düşük kimliğine sahip satırı kaldırmayacağını söylemeyi unuttum. Bu işe yararsa bu sorguyu deneyin:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

Bir grubun ikiden fazla kopyası varsa bu işe yaramaz.
OMG Ponies

11
Maalesef, MySQL, sildiğiniz tablodan seçim yapmanıza izin vermiyorERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar

1
Hatayı çözmek için "You can't specify target table 'Table' for update in FROM...": kullanın: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)MySQL'i geçici bir tablo oluşturmaya zorlar. Ancak büyük veri kümelerinde çok yavaş ... bu gibi durumlarda Andomar'ın kodunu tavsiye edeceğim, ki bu çok daha hızlı.
lepe

6

Daha hızlı yol, geçici bir tabloya farklı satırlar eklemektir. Sil komutunu kullanmak, kopyaları 8 milyon satırlık bir tablodan kaldırmak birkaç saatimi aldı. Ekleme ve farklı kullanma, sadece 13 dakika sürdü.

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;  

1
4. satırınız TRUNCATE TABLE tableNameve 5. satırınız şunu söylemelidirINSERT INTO tableName SELECT * FROM tempTableName;
Sana

5

Anlaması basit olan ve birincil anahtar olmadan çalışan bir çözüm:

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) boolean 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.


1
Bu mysql 5.7 yerde gerçekten iyi çalıştı kabul edilen çözüm artık çalışmıyor
Robin31

5

DELETE JOIN deyimini kullanarak yinelenen satırları silme MySQL, yinelenen satırları hızlı bir şekilde kaldırmak için kullanabileceğiniz DELETE JOIN deyimini sağlar.

Aşağıdaki ifade, yinelenen satırları siler ve en yüksek kimliği tutar:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

5

Basit bir yol buldum. (en son sakla)

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

4

Tüm durumlar için basit ve hızlı:

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

Hata Kodu: 1055. SELECT listesinin 2. ifadesi GROUP BY deyiminde değil ve GROUP BY deyimindeki sütunlara işlevsel olarak bağımlı olmayan birleştirilmiş 'dub.id' sütunu içeriyor; bu sql_mode = only_full_group_by ile uyumsuz
Swoogan


4

Bu, başlık, şirket ve site için aynı değerlere sahip yinelenen satırları silecektir. İlk olay korunacak ve geri kalan tüm kopyalar silinecek

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;

yavaş (5w + satır, kilit bekleme zaman aşımı) ama çalıştı
yurenchen

3

Ben google "yinelenen form mysql kaldırmak" google her zaman bu sayfayı ziyaret tutmak ama bir InnoDB mysql tabloları var çünkü benim theIGNORE çözümler için çalışmıyor

bu kod her zaman daha iyi çalışır

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 = temizlemeniz gereken tablonun adı

tableToclean_temp = geçici bir tablo oluşturuldu ve silindi


2

Bu çözüm , kopyaları bir tabloya ve benzersizleri başka bir tabloya taşıyacaktır .

-- 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

Neden birliği aldın, sadece değil SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran

2

8.0 sürümü (2018) itibariyle, MySQL nihayet pencere fonksiyonlarını desteklemektedir .

Pencere fonksiyonları hem kullanışlı hem de verimlidir. İşte bu atamayı çözmek için nasıl kullanılacağını gösteren bir çözüm.

Bir alt sorguda, gruplar ROW_NUMBER()içindeki tablodaki her kayda göre bir konum atamak için kullanabiliriz . Kopya yoksa, kayıt satır numarasını alır . Yinelenen varsa, bunlar artan (ile başlayan ) olarak numaralandırılır .column1/column2id1id1

Kayıtlar alt sorguda düzgün bir şekilde numaralandırıldığında, dış sorgu yalnızca satır numarası 1 olmayan tüm kayıtları siler.

Sorgu :

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
)

1

Tablodaki yinelenen kaydı silmek için.

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

veya

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

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;

0

Kayıtları benzersiz sütunlarla (örneğin, COL1, COL2, COL3) çoğaltmak için çoğaltılmamalıdır (tablo yapısında benzersiz 3 sütunu kaçırdığımızı ve tabloya birden çok yinelenen giriş yapıldığını varsayalım)

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;

Umut dev yardımcı olacaktır.


0

TP; TR;

Bu sorunu çözmek için bir ölçüde anlatıldığı öğretici bulunabilir mysqltutorial.org sitesinde:

MySQL'de Yinelenen Satırlar Nasıl Silinir

Yinelenen satırların üç farklı şekilde nasıl silineceği çok açık bir şekilde gösterilmiştir :

A) kullanma DELETE JOINbeyanı

B) Ara tablo kullanma

C)ROW_NUMBER() fonksiyonunu kullanma

Umarım birine yardım eder.


0

Kimlik satırına birincil anahtar eklemek unutmak bir tablo var. Olmasına rağmen kimliği auto_increment vardır. Ancak bir gün, bir şeyler yinelenen satırları ekleyen veritabanındaki mysql bin günlüğünü yeniden yürütür.

Yinelenen satırı kaldırıyorum

  1. benzersiz yinelenen satırları seçin ve dışa aktarın

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. yinelenen satırları kimliğe göre sil

  2. dışa aktarılan verilerden satırı ekleyin.

  3. Ardından kimliğe birincil anahtarı ekleyin


-2

Hangi kayıtları sildiğim konusunda biraz daha spesifik olmayı seviyorum, bu yüzden işte çözümüm:

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
)

-4

Yinelenen kayıtları bu koddan kolayca silebilirsiniz.

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

3
Bu çok kötü bir form-veritabanı görevleri, php / mysql arasında sürekli veri göndermek yerine, bir diğerinden daha iyi biliyorum çünkü DB, çok daha hızlı yapılmalıdır.
Max

-4

Bunu metin alanlarıyla yapmak zorunda kaldım ve dizinde 100 bayt sınırına rastladım.

Bunu bir sütun ekleyerek, alanların md5 karmasını yaparak ve değişikliği yaparak çözdüm.

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`);
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.