DELETE
Bir MySQL
tabloda 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.
DELETE
Bir MySQL
tabloda 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.
Yanıtlar:
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
ALTER IGNORE
.
ALTER TABLE foo ENGINE MyISAM
Etrafta koştum , sonra motoru değiştirdim.
employee
Aşağıdaki sütunları içeren bir tablonuz olduğunu varsayalım :
employee (first_name, last_name, start_date)
Yinelenen bir first_name
sü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
employee
Bir 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 unique
ve daha sonra JOIN
tam bir maça ID
kadar MAX(ID)
?
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_table
Yeni 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
)
SELECT * FROM table GROUP BY title, SID;
Her şey ne yaptığınızı ne kadar iyi bildiğinize bağlıdır.
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.
timestamp
Sı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.
ID
sütunu varsa, ON
yan tümce yalnızca ID
sütunla eşleşmelidir , başka bir şey yoktur.
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.
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 IGNORE
normal olarak başarısız olmama avantajına sahip bir tane yapıyorum Insert
iki 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.
ORDER BY
içinde SELECT
aslında onu üzerinden yapar rekor emin olmak için NoDupeTable
?
ORDER by ID Asc
incitemedi, buna rağmen cevabımı düzenleyeceğim.
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.
MAX(ID)
ya MIN(ID)
ve yerine sütun adları *
içinde SELECT FROM DupeTable
aksi takdirde sadece birini alırsınız olsa ID
'rastgele s. Aslında, birçok SQL ve hatta MySQL katı, GROUP BY
maddede belirtilmeyen her bir sütunda bir toplama işlevinin çağrılmasını gerektirir .
ID,First,Last,Notes
ve kayıtlar ile iki kayıt vardı 1,Bob,Smith,NULL
ve 2,Bob,Smith,Arrears
sonra bir yapmak SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
farklı bir kimlik dışında, aynı kaydı, 1 dönecekti. Maks (ID) dönecek 2,Bob,Smith,NULL
ve Min (ID) dönecektir 1,Bob,Smith,NULL
. Notlarda `` Arrears '' ile ikinci rekoru almak için inanıyorum bir katılma gerektirir.
İş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;
and a.id_field = b.id
LEFT JOIN
İçin b
sadece karşılaştırma ihtiyacı b.id
= a.id_field
varsayarak field_id
benzersiz otomatik artış kimliğidir. bu a.field_being_repeated = b.field_being_repeated
da yabancı. (ayrıca b.id_field
bu sorguda mevcut değil b.id
.
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.
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;
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.
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);
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`;
unique
Sü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.
unique
bir 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.
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;
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.
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)
Bu, sütunu column_name
birincil 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`);
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.
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
işte genellikle kopyaları nasıl ortadan kaldırırım
Sadece "temizlenmiş" listesi seçmek için bir DISTINCT yan tümcesi kullanabilirsiniz (ve burada bunu nasıl üzerinde çok kolay bir örneğidir).
DISTINCT
Sizi kullanmak , ilk etapta kopyalarınızla ilgili herhangi bir bilgiyi kaybeder. Bunu kullanarak kopyaları silmenin bir yolunu gösterebilir misiniz?
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;
Yinelenen verileri tablonuzdan kaldırırken yalnızca birkaç temel adım vardır:
İşte tam eğitici: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473