Jak usunąć duplikaty z tabeli MySQL?


158

Potrzebuję DELETEzduplikowanych wierszy dla określonego identyfikatora sid w MySQLtabeli.

Jak mogę to zrobić za pomocą zapytania SQL?

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

Coś takiego, ale nie wiem, jak to zrobić.


Czy wystarczy to zrobić tylko raz, czy trzeba to robić cały czas?
Billy ONeal

Czy wszystkie rekordy ze zduplikowanymi rekordami zawierają te same dane, czy też pozostałe pola różnią się od siebie? Jeśli masz pierwszą opcję, możesz po prostu usunąć wszystkie rekordy oprócz jednej, jeśli masz drugą opcję, w jaki sposób określasz, który rekord chcesz zachować?
rael_kid

Opcja @Lex First. @Billy Muszę to robić cały czas.
Ali Demirci


1
W różnych wersjach MySQL zmieniło się wiele rzeczy. Sprawdź dokładnie swoją wersję MySQL, zanim skoczysz w dół ścieżki któregokolwiek z rozwiązań tutaj.
delatbabel

Odpowiedzi:


215

usuwa to duplikaty w miejscu, bez tworzenia nowej tabeli

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

uwaga: działa dobrze tylko wtedy, gdy indeks mieści się w pamięci


26
Uwaga: zachowałoby to najstarszy zduplikowany rekord i usunąłby nowsze. Jeśli chcesz zachować najnowsze, nie możesz tego zrobić ALTER IGNORE.
Haralan Dobrev

9
Wydaje się, że nie działa z InnoDB. Pobiegłem, ALTER TABLE foo ENGINE MyISAMżeby to obejść, po czym z powrotem wymieniłem silnik.
Martin

13
to może się nie powieść na MySQL> 5.5, jeśli tak, użyj "set session old_alter_table = 1;" i "ustaw sesję old_alter_table = 0;" przed i po wypowiedzi
chillitom


2
@delatbabel Powód wycofania go jest podany na stronie, do której prowadzi łącze.
Barmar

133

Załóżmy, że masz tabelę employeez następującymi kolumnami:

employee (first_name, last_name, start_date)

Aby usunąć wiersze ze zduplikowaną first_namekolumną:

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

1
Pozostały rekord będzie miał maksymalny lub minimalny identyfikator w swojej duplikującej się grupie?
Frozen Flame

Pozostały rekord będzie miał minimalny identyfikator, ponieważ jako jedyny nie spełnia warunku do usunięcia
Pablo Guerrero

1
Wygląda na to, że łączenie się employeeze sobą dla jednego dopasowania indeksu i jedno >sprawdzenie indeksu będzie powolne w przypadku dużych tabel. Czy nie byłoby lepiej, SELECT MAX(ID) FROM t GROUP BY uniquea potem JOINdokładnym dopasowaniem IDdo MAX(ID)?
ebyrob

1
Świetna odpowiedź! Zaoszczędziłem mój czas!
Nesar

56

Następnie usuń duplikaty wszystkich identyfikatorów SID, nie tylko jednego.

Ze stołem temp

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

DROP TABLE table;
RENAME TABLE table_temp TO table;

Ponieważ temp_tablejest świeżo utworzony, nie ma indeksów. Musisz je odtworzyć po usunięciu duplikatów. Możesz sprawdzić, z jakimi indeksami masz w tabeliSHOW INDEXES IN table

Bez tabeli temp:

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
Funkcja GROUP -ing tworzy tylko jeden wiersz wynikowy dla każdej kombinacji wartości pól, według których grupujesz. Więc duplikaty zostaną usunięte.
Kamil Szot

4
Lubię pierwszy sposób, zbyt elegancki tutaj! : B
AgelessEssence

1
@fiacre Możesz tymczasowo wyłączyć sprawdzanie kluczy obcych: stackoverflow.com/questions/15501673/… Możesz także ryzykować usunięcie niektórych wierszy, do których odnoszą się inne tabele, ale możesz kontrolować, które rekordy są pobierane do dedupowanej tabeli, zmieniając zapytanie SELECT * FROM table GROUP BY title, SID;Wszystko zależy od tego, jak dobrze wiesz, co robisz.
Kamil Szot

1
@ahnbizcad Możesz użyć tabeli tymczasowej, ale wtedy będziesz musiał skopiować dane z tabeli tymczasowej do zwykłej tabeli. Jeśli używasz prawdziwego stołu, możesz po prostu usunąć stary z duplikatami i zmienić nazwę nowego, bez duplikatu na stare.
Kamil Szot

1
Metoda "bez tabeli temp" jest najbliższa najlepszemu rozwiązaniu, jednak uważaj na obsługę ONLY_FULL_GROUP_BY, która zmieniła się w MySQL 5.7.5: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html Mam to do pracy, zastępując „SELECT id” tekstem „SELECT ANY_VALUE (id) AS id”
delatbabel,

53

Usuwanie zduplikowanych wierszy w miejscu MySQL, (zakładając, że masz kolumnę sygnatury czasowej do sortowania):

Utwórz tabelę i wstaw kilka wierszy:

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)

Usuń duplikaty w miejscu:

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)

Gotowe, zduplikowane wiersze są usuwane, zachowywany jest ostatni według sygnatury czasowej.

Dla tych z Was, którzy nie mają sygnatury czasowej ani unikalnej kolumny.

Nie masz timestamp unikatowej kolumny indeksu do sortowania? Żyjesz w stanie degeneracji. Będziesz musiał wykonać dodatkowe czynności, aby usunąć zduplikowane wiersze.

utwórz tabelę pingwinów i dodaj kilka wierszy

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

zrobić klon pierwszej tabeli i skopiować do niej.

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

Agregat max działa na nowym indeksie moo:

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; 

obserwować i porządkować

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

Co robi ta duża instrukcja usuwania SQL?

Pingwiny stołowe z aliasem „a” pozostają połączone z podzbiorem pingwinów stołowych zwanych aliasami „b”. W prawej tabeli „b”, która jest podzbiorem, znajduje się maksymalny znacznik czasu [lub max moo] pogrupowany według kolumn foo i bar. Jest to dopasowane do tabeli „a” po lewej stronie. (foo, bar, baz) po lewej stronie ma każdy wiersz w tabeli. Podzbiór „b” po prawej stronie ma (maxtimestamp, foo, bar), który jest dopasowywany do lewej tylko na tym, który JEST maksymalny.

Każdy wiersz inny niż maksymalna ma wartość maxtimestamp równą NULL. Przefiltruj te wiersze NULL i masz zestaw wszystkich wierszy pogrupowanych według foo i bar, który nie jest najnowszym bazem sygnatury czasowej. Usuń te.

Przed uruchomieniem wykonaj kopię zapasową tabeli.

Zapobiegaj ponownemu występowaniu tego problemu na tym stole:

Jeśli to zadziałało i ugasiło pożar w „zduplikowanym rzędzie”. Wspaniały. Teraz zdefiniuj nowy złożony unikatowy klucz w tabeli (w tych dwóch kolumnach), aby w pierwszej kolejności zapobiec dodawaniu większej liczby duplikatów.

Podobnie jak w przypadku dobrego układu odpornościowego, złe wiersze nie powinny nawet trafiać do stołu w momencie wstawiania. Później wszystkie programy dodające duplikaty będą emitować swój protest, a kiedy je naprawisz, ten problem nigdy się nie pojawi.


6
oceń wyłącznie dla odniesienia do Madagaskaru!
Michael Wiggins

1
Oceniony, ponieważ to świetna odpowiedź i świetne sugestie, dzięki, Eric pracował lepiej niż jakakolwiek inna odpowiedź.
johan

4
Uwaga: Jeśli twoja tabela ma IDkolumnę z automatycznym zwiększaniem, ONklauzula musi tylko pasować do IDkolumny, nic więcej.
ebyrob

1
Podoba mi się szczegółowe wyjaśnienie, ale ... Jeśli dobrze rozumiem, ta odpowiedź wykorzystuje sygnaturę czasową do rozróżnienia rekordów. W tym sensie rekordy nie są zduplikowane. Co jeśli nie masz znacznika czasu do rozróżnienia rekordów, tj. Wszystkie kolumny są takie same dla 2 lub więcej rekordów?
Rsc Rsc

1
@RscRsc Jeśli nie masz kolumny z sygnaturą czasową lub unikalnego indeksu, do którego można zastosować maksymalne zagregowanie, wygląda na to, że musisz zduplikować tabelę, dodać unikalny indeks, zastosować instrukcję usuwania, a następnie zastąpić skopiowaną tabelę z powrotem oryginalną . Zmieniłem odpowiedź, aby odzwierciedlić te instrukcje.
Eric Leschinski

16

Po tym, jak sam natknąłem się na ten problem, na ogromnej bazie danych, nie byłem pod wrażeniem wydajności żadnej z innych odpowiedzi. Chcę zachować tylko ostatni zduplikowany wiersz, a resztę usunąć.

W przypadku instrukcji z jednym zapytaniem, bez tabeli tymczasowej, działało to najlepiej,

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

Jedynym zastrzeżeniem jest to, że muszę uruchamiać zapytanie wiele razy, ale mimo to okazało się, że działa lepiej niż inne opcje.


1
Pragmatyczne rozwiązanie! Pracował dla mnie - około 20s dla 2m + wiersz tabeli innodb. Kiedyś użyłem go kilka razy i było kilku przestępców z dużą liczbą duplikatów, wykonałem pracę ręcznie.
Troy Wray

1
Pracował dla mnie za jednym zamachem, super!
Murwa

Musi być wykonywany wiele razy, jeśli duplikaty dla którejkolwiek kolumny są większe niż 2x
PayteR

@PayteR, o którym mowa w odpowiedzi „Jedynym zastrzeżeniem jest to, że muszę wielokrotnie uruchamiać zapytanie”
seaders

13

To zawsze wydaje się działać dla mnie:

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

Który zachowuje najniższy identyfikator dla każdego z dupleksów i reszty rekordów bez dupleksu.

Podjąłem również następujące kroki, aby problem z kopiowaniem nie występował już po usunięciu:

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

Innymi słowy, tworzę duplikat pierwszej tabeli, dodaję unikalny indeks do pól, których nie chcę mieć duplikatów, a następnie wykonuję operację, Insert IGNOREktóra ma tę zaletę, że nie zawodzi jak zwykleInsert przy pierwszej próbie dodania zduplikowany rekord oparty na dwóch polach i raczej ignoruje takie rekordy.

Poruszając się dalej, niemożliwe staje się utworzenie jakichkolwiek zduplikowanych rekordów na podstawie tych dwóch pól.


1
Czy nie potrzebowałbyś wpisu ORDER BYw, SELECTaby mieć pewność, który rekord trafi do katalogu NoDupeTable?
ebyrob

@ebyrob, jak sądzę, chyba że poinstruowano inaczej, wybierze najniższy identyfikator w przypadku braku innych kryteriów. Oczywiście ORDER by ID Ascnic nie zaszkodzi, więc i tak zmienię odpowiedź.
user3649739

@ebyrob Sorry my bad. O ile mi wiadomo, opcja Order by nie zadziała w tym wyborze. Zamówienie przed końcem selekcji uporządkuje tylko duplikaty znalezione według najniższego identyfikatora znalezionego w każdej parze. Alternatywnie możesz zrobić Select Max(ID)a, Order by Max(ID)ale wystarczy odwrócić kolejność wkładek. Wydaje mi się, że uzyskanie najwyższego identyfikatora wymagałoby bardziej złożonego łączenia typu select, ponieważ niezależnie od tego, jak zamówisz powyżej, będziesz pobierać wartości pól z niższego identyfikatora.
user3649739

Właściwie nie jestem pewien, o czym myślę przy zamówieniu. Zdecydowanie wolałbyś nazwy kolumn MAX(ID)lub MIN(ID)i zamiast *w SELECT FROM DupeTablechociaż, w przeciwnym razie po prostu otrzymasz IDlosowo jedną z kolumn . W rzeczywistości wiele SQL, a nawet MySQL, wymaga wywołania funkcji agregującej w każdej kolumnie, która nie została określona w GROUP BYklauzuli.
ebyrob

@ebyrob Podczas testowania Max (ID) Min (ID) nie rób nic poza zwróceniem ID rekordu Max lub Mind. W każdym przypadku pobiera te same rekordy. Więc gdybym miał dwa rekordy z polami ID,First,Last,Notesi rekordami, 1,Bob,Smith,NULLa 2,Bob,Smith,Arrearsnastępnie wykonanie a SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastzwróciłoby ten sam rekord, 1, z wyjątkiem z innym identyfikatorem. Zwróci wartość Max (ID), 2,Bob,Smith,NULLa Min (ID) 1,Bob,Smith,NULL. Wydaje mi się, że uzyskanie drugiego rekordu z napisem „Zaległości” w notatkach wymaga połączenia.
user3649739

7

Poniższe działa dla wszystkich tabel

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

6

Oto prosta odpowiedź:

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;

To dobra odpowiedź, z wyjątkiem małego błęduand a.id_field = b.id
Vikrant Goel

LEFT JOINAby btylko musi porównać b.id= a.id_fieldzakładając field_idto unikatowy identyfikator automatycznego przyrostu. tak a.field_being_repeated = b.field_being_repeatedjest obce. (również b.id_fieldnie występuje w tym zapytaniu to b.id.
ebyrob

6

To działa dla mnie, aby usunąć stare rekordy:

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

Możesz zamienić min (e.id) na max (e.id), aby usunąć najnowsze rekordy.


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
Okazało się, że jest to znacznie bardziej wydajne rozwiązanie niż te powyżej
Christian Butzke

5

Powyżej znajduję rozwiązanie Wernera najwygodniejsze, ponieważ działa niezależnie od obecności klucza podstawowego, nie zadziera z tabelami, wykorzystuje przyszłościowy zwykły sql, jest bardzo zrozumiałe.

Jak wspomniałem w swoim komentarzu, to rozwiązanie nie zostało jednak właściwie wyjaśnione. Więc to jest moje, oparte na tym.

1) dodaj nową kolumnę logiczną

alter table mytable add tokeep boolean;

2) dodaj ograniczenie do zduplikowanych kolumn ORAZ nowej kolumny

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

3) ustaw kolumnę logiczną na wartość true. To się powiedzie tylko w jednym ze zduplikowanych wierszy z powodu nowego ograniczenia

update ignore mytable set tokeep = true;

4) usuń wiersze, które nie zostały oznaczone jako tokeep

delete from mytable where tokeep is null;

5) upuść dodaną kolumnę

alter table mytable drop tokeep;

Proponuję zachować dodane ograniczenie, aby w przyszłości uniknąć nowych duplikatów.


4

Ta procedura usunie wszystkie duplikaty (w tym wielokrotności) z tabeli, zachowując ostatni duplikat. Jest to rozszerzenie opcji Pobieranie ostatniego rekordu w każdej grupie

Mam nadzieję, że to komuś się przyda.

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

Kolejny łatwy sposób ... używając UPDATE IGNORE:

Musisz użyć indeksu dla jednej lub więcej kolumn (indeks typu). Utwórz nową tymczasową kolumnę odniesienia (nie będącą częścią indeksu). W tej kolumnie oznaczasz unikaty w, aktualizując je klauzulą ​​ignore. Krok po kroku:

Dodaj tymczasową kolumnę odniesienia, aby oznaczyć unikatów:

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

=> to doda kolumnę do twojej tabeli.

Zaktualizuj tabelę, spróbuj oznaczyć wszystko jako unikalne, ale zignoruj ​​możliwe błędy spowodowane problemem zduplikowanego klucza (rekordy zostaną pominięte):

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

=> odkryjesz, że Twoje zduplikowane rekordy nie zostaną oznaczone jako unikalne = 'Tak', innymi słowy, tylko jeden z każdego zestawu zduplikowanych rekordów zostanie oznaczony jako unikalny.

Usuń wszystko, co nie jest unikalne:

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

=> Spowoduje to usunięcie wszystkich zduplikowanych rekordów.

Upuść kolumnę ...

ALTER TABLE `yourtable` DROP `unique`;

Myślę, że to najlepsze rozwiązanie, ponieważ nie powoduje bałaganu w tabelach i używa zwykłego prostego sql. Jedna rzecz powinna być jasna: uniquekolumna MUSI zostać dodana do unikalnego ograniczenia razem z kolumnami, które są obecnie zduplikowane, w przeciwnym razie całość nie zadziała, ponieważ SET unique= 'Yes' nigdy nie zawiedzie.
xtian

Należy również pamiętać, że uniquejest to słowo kluczowe mysql. Musi więc mieć znaki grawitacyjne (jak już są poprawnie wyświetlone). Użycie innego słowa na oznaczenie kolumny może być wygodniejsze.
Torsten,

2

Usuwanie duplikatów w tabelach MySQL jest częstym problemem, który zwykle wiąże się z określonymi potrzebami. Jeśli ktoś jest zainteresowany, tutaj ( Usuń zduplikowane wiersze w MySQL ) wyjaśniam, jak używać tabeli tymczasowej do usuwania duplikatów MySQL w niezawodny i szybki sposób, również do obsługi źródeł dużych zbiorów danych (z przykładami dla różnych przypadków użycia).

Ali , w twoim przypadku możesz uruchomić coś takiego:

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

To generuje błąd SQL (1093) w niektórych konfiguracjach i wersjach MySQL.
ebyrob

0

Odpowiedź Love @ eric, ale wydaje się nie działać, jeśli masz naprawdę duży stół (dostaję, 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 okaygdy próbuję go uruchomić). Więc ograniczyłem zapytanie sprzężenia do rozważenia tylko zduplikowanych wierszy i otrzymałem:

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

Klauzula WHERE w tym przypadku umożliwia MySQL ignorowanie każdego wiersza, który nie ma duplikatu, a także ignoruje, jeśli jest to pierwsza instancja duplikatu, więc tylko kolejne duplikaty będą ignorowane. Zmień MIN(baz)na, MAX(baz)aby zachować ostatnią instancję zamiast pierwszej.


0

Działa to w przypadku dużych tabel:

 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;

Aby usunąć najstarszą zmianę max(id)wmin(id)


0

To tutaj spowoduje, że kolumna stanie column_namesię kluczem podstawowym, a tymczasem zignoruje wszystkie błędy. Więc usunie wiersze ze zduplikowaną wartością dla column_name.

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

Jak zauważono w komentarzach do poprzedniej odpowiedzi, nie działa to już w 5.7.
Barmar

0

Myślę, że to zadziała, kopiując tabelę i opróżniając ją, a następnie umieszczając z powrotem tylko odrębne wartości, ale sprawdź to dokładnie przed wykonaniem tego na dużych ilościach danych.

Tworzy kopię Twojego stołu

utwórz tabelę temp_table jak stara nazwa tabeli; wstaw temp_table select * from oldtablename;

Opróżnia oryginalny stół

DELETE * from oldtablename;

Kopiuje wszystkie odrębne wartości ze skopiowanej tabeli z powrotem do oryginalnej tabeli

INSERT stara nazwa_tablicy SELECT * z grupy temp_table wg imienia, nazwiska, ur

Usuwa tabelę tymczasową.

Drop Table temp_table

Musisz pogrupować według wszystkich pól, które chcesz rozróżnić.


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

to nie działa na twoją prośbę, czy mógłbyś to poprawić?
Samir Guiderk

0

oto jak zwykle eliminuję duplikaty

  1. dodaj tymczasową kolumnę, nazwij ją, jak chcesz (będę określał jako aktywną)
  2. pogrupuj według pól, które Twoim zdaniem nie powinny być duplikowane i ustaw ich aktywne na 1, grupowanie według wybierze tylko jedną z zduplikowanych wartości (nie wybierze duplikatów) dla tych kolumn
  3. usuń te z aktywnym zerem
  4. aktywna kolumna upuszczania
  5. opcjonalnie (jeśli pasuje do twoich celów), dodaj unikalny indeks dla tych kolumn, aby nie mieć ponownie duplikatów

-2

Możesz po prostu użyć klauzuli DISTINCT, aby wybrać „wyczyszczoną” listę (a tutaj jest bardzo prosty przykład, jak to zrobić).


Jak to odpowiada na pytanie? Korzystanie z DISTINCTCiebie powoduje utratę wszelkich informacji o duplikatach, które mogłeś mieć w pierwszej kolejności. Czy możesz pokazać sposób usuwania duplikatów za jego pomocą?
luk2302

-3

Czy to zadziała, jeśli je policzysz, a następnie dodasz ograniczenie do zapytania usuwającego, pozostawiając tylko jedno?

Na przykład, jeśli masz dwa lub więcej, napisz zapytanie w ten sposób:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

Aby usunąć zduplikowane dane z tabeli, wystarczy wykonać kilka podstawowych czynności:

  • Zrób kopię zapasową swojego stołu!
  • Znajdź zduplikowane wiersze
  • Usuń zduplikowane wiersze

Oto pełny samouczek: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473


Czy to działa, jeśli tylko unikalny identyfikator jest inny. Eğer sadece benzersiz id farklı ise de bu işe yarar mı?
Andrew

Domyślnie opisana tutaj metoda nie działa dla wersji MySQL> 5.7.5. Wynika to z obsługi ONLY_FULL_GROUP_BY. Zobacz tutaj: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.