Wie lösche ich Duplikate in einer MySQL-Tabelle?


158

Ich muss DELETEZeilen für die angegebene Seite in einer MySQLTabelle duplizieren .

Wie kann ich das mit einer SQL-Abfrage machen?

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

So etwas, aber ich weiß nicht, wie ich es machen soll.


Müssen Sie es nur einmal tun oder müssen Sie es die ganze Zeit tun?
Billy ONeal

Haben die Datensätze mit den doppelten Datensätzen alle dieselben Daten oder unterscheiden sich die übrigen Felder voneinander? Wenn Sie die erste Option haben, können Sie einfach alle Datensätze bis auf einen löschen. Wenn Sie die zweite Option haben, wie bestimmen Sie, welchen Datensatz Sie behalten möchten?
rael_kid

@Lex Erste Option. @ Billy Ich muss es die ganze Zeit tun.
Ali Demirci

1
Mögliches Duplikat von Doppelte Zeilen in MySQL entfernen
Basilevs

1
Es gibt viele Dinge, die sich hier in verschiedenen Versionen von MySQL geändert haben. Überprüfen Sie Ihre MySQL-Version sorgfältig, bevor Sie den Weg einer der hier aufgeführten Lösungen beschreiten.
delatbabel

Antworten:


215

Dadurch werden vorhandene Duplikate entfernt, ohne dass eine neue Tabelle erstellt werden muss

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

Hinweis: Funktioniert nur gut, wenn der Index in den Speicher passt


26
Hinweis: Dies würde den ältesten doppelten Datensatz behalten und die neueren löschen. Wenn Sie das Neueste behalten möchten, können Sie dies nicht tun ALTER IGNORE.
Haralan Dobrev

9
Scheint nicht mit InnoDB zu funktionieren. Ich rannte ALTER TABLE foo ENGINE MyISAMlos, um es zu umgehen, und wechselte danach den Motor zurück.
Martin

13
Dies kann unter MySQL> 5.5 fehlschlagen. Verwenden Sie in diesem Fall "set session old_alter_table = 1;" und "setze Sitzung old_alter_table = 0;" vor und nach der Aussage
chillitom


2
@delatbabel Der Grund für die Ablehnung ist auf der Seite angegeben, auf die Sie verlinkt haben.
Barmar

133

Angenommen, Sie haben eine Tabelle employeemit den folgenden Spalten:

employee (first_name, last_name, start_date)

So löschen Sie die Zeilen mit einer doppelten first_nameSpalte:

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

1
Der verbleibende Datensatz hat die maximale oder minimale ID in seiner duplizierenden Gruppe?
Frozen Flame

Der verbleibende Datensatz hat die Mindest-ID, da er der einzige ist, der die zu löschende Bedingung nicht erfüllt
Pablo Guerrero

1
Scheint, als würde man employeesich für eine Indexübereinstimmung gegen sich selbst anschließen, und eine >Überprüfung eines Index wird für große Tabellen langsam sein. Wäre es nicht besser zu SELECT MAX(ID) FROM t GROUP BY uniqueund dann JOINzu einer exakten Übereinstimmung von IDzu MAX(ID)?
Ebyrob

1
Gute Antwort! Hat mir Zeit gespart!
Nesar

56

Entfernen Sie anschließend Duplikate für alle SIDs, nicht nur für einzelne.

Mit temporärer Tabelle

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

DROP TABLE table;
RENAME TABLE table_temp TO table;

Da temp_tablees frisch erstellt wurde, hat es keine Indizes. Sie müssen sie neu erstellen, nachdem Sie Duplikate entfernt haben. Sie können überprüfen, mit welchen Indizes Sie in der Tabelle sindSHOW INDEXES IN table

Ohne temporäre Tabelle:

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 erzeugt nur eine Ergebniszeile für jede Kombination von Werten von Feldern, nach denen Sie gruppieren. Duplikate werden also entfernt.
Kamil Szot

4
Ich mag den ersten Weg, zu elegant hier! : B
AgelessEssence

1
@fiacre Sie können Fremdschlüsselprüfungen vorübergehend deaktivieren: stackoverflow.com/questions/15501673/… Sie könnten auch riskieren, einige der Zeilen zu entfernen, auf die sich andere Tabellen beziehen, aber Sie können steuern, welche Datensätze in die dedupierte Tabelle aufgenommen werden, indem Sie die Abfrage ändern SELECT * FROM table GROUP BY title, SID;Es hängt alles davon ab, wie gut Sie wissen, was Sie tun.
Kamil Szot

1
@ahnbizcad Sie könnten eine temporäre Tabelle verwenden, müssen dann aber die Daten von der temporären Tabelle in die reguläre Tabelle zurückkopieren. Wenn Sie eine echte Tabelle verwenden, können Sie einfach die alte mit den Duplikaten löschen und die neue umbenennen, ohne das Duplikat in den Namen der alten.
Kamil Szot

1
Die Methode "ohne temporäre Tabelle" kommt der besten Lösung am nächsten. Achten Sie jedoch auf die Behandlung mit ONLY_FULL_GROUP_BY, die sich in MySQL 5.7.5 geändert hat: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html Ich habe dies erhalten zu arbeiten, indem "SELECT id" durch "SELECT ANY_VALUE (id) AS id" ersetzt wird
delatbabel

53

Löschen doppelter Zeilen in MySQL an Ort und Stelle (vorausgesetzt, Sie haben eine Zeitstempelspalte zum Sortieren) exemplarische Vorgehensweise:

Erstellen Sie die Tabelle und fügen Sie einige Zeilen ein:

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)

Entfernen Sie die vorhandenen Duplikate:

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)

Sie sind fertig, doppelte Zeilen werden entfernt, die letzte nach Zeitstempel bleibt erhalten.

Für diejenigen unter Ihnen ohne Zeitstempel oder eindeutige Spalte.

Sie haben keine timestampoder eine eindeutige Indexspalte zum Sortieren? Du lebst in einem Zustand der Entartung. Sie müssen zusätzliche Schritte ausführen, um doppelte Zeilen zu löschen.

Erstellen Sie die Pinguintabelle und fügen Sie einige Zeilen hinzu

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

Erstellen Sie einen Klon der ersten Tabelle und kopieren Sie ihn hinein.

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

Das maximale Aggregat arbeitet mit dem neuen Moo-Index:

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; 

beobachten und aufräumen

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

Was macht diese große SQL-Löschanweisung?

Tabellenpinguine mit dem Alias ​​'a' werden in einer Teilmenge von Tabellenpinguinen mit dem Namen 'b' zusammengefasst. Die rechte Tabelle 'b', die eine Teilmenge ist, findet den maximalen Zeitstempel (oder das maximale Moo), gruppiert nach den Spalten foo und bar. Dies ist auf die linke Tabelle 'a' abgestimmt. (foo, bar, baz) links hat jede Zeile in der Tabelle. Die rechte Teilmenge 'b' hat eine (Maxtimestamp, foo, bar), die nur auf diejenige abgestimmt ist, die die max.

Jede Zeile, die nicht das Maximum ist, hat den Wert maxtimestamp von NULL. Filtern Sie nach diesen NULL-Zeilen und Sie haben eine Reihe aller Zeilen, die nach foo und bar gruppiert sind und nicht die neueste Zeitstempel-Basis sind. Löschen Sie diese.

Erstellen Sie eine Sicherungskopie der Tabelle, bevor Sie diese ausführen.

Verhindern Sie, dass dieses Problem in dieser Tabelle jemals wieder auftritt:

Wenn Sie dies zum Laufen gebracht haben und Ihr "Duplicate Row" -Feuer gelöscht haben. Toll. Definieren Sie nun einen neuen zusammengesetzten eindeutigen Schlüssel in Ihrer Tabelle (in diesen beiden Spalten), um zu verhindern, dass überhaupt weitere Duplikate hinzugefügt werden.

Wie bei einem guten Immunsystem sollten die schlechten Reihen zum Zeitpunkt des Einfügens nicht einmal in die Tabelle zugelassen werden. Später senden alle Programme, die Duplikate hinzufügen, ihren Protest, und wenn Sie sie beheben, tritt dieses Problem nie wieder auf.


6
Bewerten Sie nur für die Madagaskar Referenz!
Michael Wiggins

1
Bewertet, da dies eine großartige Antwort und großartige Vorschläge sind, danke Eric hat besser gearbeitet als jede andere Antwort da draußen.
Johan

4
Hinweis: Wenn Ihre Tabelle eine IDSpalte für das automatische Inkrementieren enthält , muss die ONKlausel nur mit der IDSpalte übereinstimmen , sonst nichts.
Ebyrob

1
Ich mag die ausführliche Erklärung, aber ... Wenn ich das richtig verstehe, verwendet diese Antwort den Zeitstempel, um zwischen Datensätzen zu unterscheiden. In diesem Sinne sind Datensätze nicht doppelt vorhanden. Was wäre, wenn Sie keinen Zeitstempel hätten, um zwischen Datensätzen zu unterscheiden, dh alle Spalten sind für zwei oder mehr Datensätze gleich?
Rsc Rsc

1
@RscRsc Wenn Sie keine Zeitstempelspalte oder keinen eindeutigen Index haben, auf den das maximale Aggregat angewendet werden kann, müssen Sie die Tabelle duplizieren, einen eindeutigen Index hinzufügen, die delete-Anweisung anwenden und die kopierte Tabelle wieder durch das Original ersetzen . Ich habe die Antwort geändert, um diese Anweisungen wiederzugeben.
Eric Leschinski

16

Nachdem ich selbst auf dieses Problem in einer riesigen Datenbank gestoßen war, war ich von der Leistung der anderen Antworten nicht ganz beeindruckt. Ich möchte nur die letzte doppelte Zeile behalten und den Rest löschen.

In einer Anweisung mit einer Abfrage ohne temporäre Tabelle funktionierte dies am besten für mich.

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

Die einzige Einschränkung ist, dass ich die Abfrage mehrmals ausführen muss, aber trotzdem fand ich, dass sie für mich besser funktioniert als die anderen Optionen.


1
Pragmatische Lösung! Arbeitete für mich - ungefähr 20s für einen 2 m + Reihe innodb Tisch. Nachdem ich es ein paar Mal benutzt hatte und nur wenige Straftäter mit einer hohen Anzahl von Duplikaten hatten, beendete ich den Job manuell.
Troy Wray

1
Hat auf einen Schlag für mich gearbeitet, großartig!
Murwa

Es muss mehrmals ausgeführt werden, wenn Duplikate für Spalten mehr als 2x sind
PayteR

@ PayteR, die in der Antwort angegeben ist, "Die einzige Einschränkung ist, dass ich die Abfrage mehrmals
ausführen muss

13

Das scheint bei mir immer zu funktionieren:

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

Dadurch wird die niedrigste ID für jeden der Dupes und den Rest der Nicht-Dupe-Datensätze beibehalten.

Ich habe auch Folgendes unternommen, damit das Dupe-Problem nach dem Entfernen nicht mehr auftritt:

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

Mit anderen Worten, ich erstelle ein Duplikat der ersten Tabelle, füge einen eindeutigen Index für die Felder hinzu, von denen ich keine Duplikate möchte, und mache dann einen, Insert IGNOREder den Vorteil hat, dass er nicht wie gewohnt fehlschlägtInsert dass er beim ersten Versuch ausfällt ein doppelter Datensatz, der auf den beiden Feldern basiert und solche Datensätze eher ignoriert.

Beim Verschieben wird es unmöglich, doppelte Datensätze basierend auf diesen beiden Feldern zu erstellen.


1
Würdest du nicht eine ORDER BYin der brauchen SELECT, um sicher zu sein, welche Platte es tatsächlich in die schafft NoDupeTable?
Ebyrob

@ebyrob Ich glaube, wenn nicht anders angegeben, wird die niedrigste ID ausgewählt, wenn keine anderen Kriterien vorliegen. Natürlich ORDER by ID Asckonnte es nicht schaden, also werde ich meine Antwort trotzdem bearbeiten.
user3649739

@ebyrob Sorry mein schlechtes. Die Bestellung von funktioniert in dieser Auswahl meines Wissens nicht. Bei einer Bestellung am Ende der Auswahl werden nur die Duplikate sortiert, die mit der niedrigsten ID in jedem Paar gefunden wurden. Alternativ können Sie ein Select Max(ID)und dann Order by Max(ID)ausführen, aber alles, was Sie tun würden, ist die Reihenfolge der Einfügung umzukehren. Um die höchste ID zu erhalten, ist meines Erachtens ein komplexerer Select-Join erforderlich, da unabhängig davon, wie Sie oben bestellen, die Feldwerte von der niedrigeren ID abgerufen werden.
user3649739

Eigentlich nicht sicher, was ich mit Bestellung von dachte. Sie möchten auf jeden Fall MAX(ID)oder MIN(ID)und Spaltennamen anstatt *in der SELECT FROM DupeTableobwohl, sonst erhalten Sie nur einen der IDzufällig. Tatsächlich erfordern viele SQLs und sogar MySQL strict das Aufrufen einer Aggregatfunktion für jede Spalte, die nicht in der GROUP BYKlausel angegeben ist.
Ebyrob

@ebyrob Beim Testen der Max (ID) Min (ID) nichts anderes tun, als die ID des Max- oder Mind-Datensatzes zurückzugeben. In jedem Fall greift nach den gleichen Aufzeichnungen. Wenn ich also zwei Datensätze mit Feldern ID,First,Last,Notesund Datensätzen hätte 1,Bob,Smith,NULLund 2,Bob,Smith,Arrearsdann a ausführen SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastwürde, würden beide denselben Datensatz 1 zurückgeben, außer mit einer anderen ID. Max (ID) würde zurückkehren 2,Bob,Smith,NULLund Min (ID) würde zurückkehren 1,Bob,Smith,NULL. Um die zweite Platte mit "Arrears" in den Notizen zu erhalten, ist meiner Meinung nach ein Join erforderlich.
user3649739

7

Das Folgende funktioniert für alle Tabellen

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

6

Hier ist eine einfache Antwort:

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;

Es ist eine gute Antwort, außer einem kleinen Fehlerand a.id_field = b.id
Vikrant Goel

Das LEFT JOINto muss bnur verglichen werden b.id= a.id_fieldvorausgesetzt, es field_idhandelt sich um eine eindeutige automatische Inkrement-ID. so a.field_being_repeated = b.field_being_repeatedist irrelevant. (existiert auch b.id_fieldnicht in dieser Abfrage, es ist b.id.
Ebyrob

6

Diese Arbeit für mich, um alte Aufzeichnungen zu entfernen:

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

Sie können min (e.id) durch max (e.id) ersetzen, um die neuesten Datensätze zu entfernen.


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
Ich fand, dass eine weitaus performantere Lösung als die oben genannten
Christian Butzke

5

Ich finde Werners Lösung oben am bequemsten, da sie unabhängig vom Vorhandensein eines Primärschlüssels funktioniert, nicht mit Tabellen herumspielt, zukunftssicheres einfaches SQL verwendet und sehr verständlich ist.

Wie ich in meinem Kommentar festgestellt habe, wurde diese Lösung jedoch nicht richtig erklärt. Das ist also meins, basierend darauf.

1) Fügen Sie eine neue boolesche Spalte hinzu

alter table mytable add tokeep boolean;

2) Fügen Sie eine Einschränkung für die duplizierten Spalten UND die neue Spalte hinzu

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

3) Setzen Sie die boolesche Spalte auf true. Dies ist aufgrund der neuen Einschränkung nur für eine der duplizierten Zeilen erfolgreich

update ignore mytable set tokeep = true;

4) Löschen Sie Zeilen, die nicht als tokeep markiert wurden

delete from mytable where tokeep is null;

5) Löschen Sie die hinzugefügte Spalte

alter table mytable drop tokeep;

Ich schlage vor, dass Sie die von Ihnen hinzugefügte Einschränkung beibehalten, damit neue Duplikate in Zukunft verhindert werden.


4

Bei diesem Verfahren werden alle Duplikate (einschließlich Vielfache) in einer Tabelle entfernt, wobei das letzte Duplikat beibehalten wird. Dies ist eine Erweiterung von Abrufs des letzten Datensatzes in jeder Gruppe

Hoffe das ist nützlich für jemanden.

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

Ein weiterer einfacher Weg ... mit UPDATE IGNORE:

Sie müssen einen Index für eine oder mehrere Spalten verwenden (Typindex). Erstellen Sie eine neue temporäre Referenzspalte (nicht Teil des Index). In dieser Spalte markieren Sie die Unikate, indem Sie sie mit der Ignorierklausel aktualisieren. Schritt für Schritt:

Fügen Sie eine temporäre Referenzspalte hinzu, um die Unikate zu markieren:

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

=> Dadurch wird Ihrer Tabelle eine Spalte hinzugefügt.

Aktualisieren Sie die Tabelle, versuchen Sie, alles als eindeutig zu markieren, ignorieren Sie jedoch mögliche Fehler aufgrund eines Problems mit doppelten Schlüsseln (Datensätze werden übersprungen):

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

=> Sie werden feststellen, dass Ihre doppelten Datensätze nicht als eindeutig markiert werden = 'Ja', dh nur einer von jedem Satz doppelter Datensätze wird als eindeutig markiert.

Löschen Sie alles, was nicht eindeutig ist:

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

=> Dadurch werden alle doppelten Datensätze entfernt.

Lass die Spalte fallen ...

ALTER TABLE `yourtable` DROP `unique`;

Ich denke, dies ist die beste Lösung, da es nicht mit Tabellen zu tun hat und einfach nur SQL verwendet. Eines sollte nur klargestellt werden: Die uniqueSpalte MUSS zusammen mit den aktuell duplizierten Spalten zu einer eindeutigen Einschränkung hinzugefügt werden, da sonst das Ganze nicht funktioniert, da SET unique= 'Yes' niemals fehlschlagen würde.
Xtian

uniqueBeachten Sie auch, dass dies ein MySQL-Schlüsselwort ist. Es müssen also die Backticks vorhanden sein (wie bereits richtig angezeigt). Die Verwendung eines anderen Wortes für die Spalte ist möglicherweise bequemer.
Torsten

2

Das Löschen von Duplikaten in MySQL-Tabellen ist ein häufiges Problem, das normalerweise mit bestimmten Anforderungen verbunden ist. Falls jemand interessiert ist, hier ( Entfernen Sie doppelte Zeilen in MySQL erkläre ich ), wie man eine temporäre Tabelle verwendet, um MySQL-Duplikate zuverlässig und schnell zu löschen, auch gültig für den Umgang mit großen Datenquellen (mit Beispielen für verschiedene Anwendungsfälle).

Ali , in deinem Fall kannst du so etwas ausführen:

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

Dies erzeugt bei einigen Konfigurationen und Versionen von MySQL einen SQL-Fehler (1093).
Ebyrob

0

Die Antwort von Love @ eric, aber es scheint nicht zu funktionieren, wenn Sie einen wirklich großen Tisch haben (ich bekomme, 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 okaywenn ich versuche, ihn zu betreiben). Daher habe ich die Join-Abfrage auf die doppelten Zeilen beschränkt und am Ende Folgendes erhalten:

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

Die WHERE-Klausel in diesem Fall ermöglicht es MySQL, jede Zeile zu ignorieren, die kein Duplikat enthält, und wird auch ignoriert, wenn dies die erste Instanz des Duplikats ist, sodass nur nachfolgende Duplikate ignoriert werden. Wechseln Sie MIN(baz)zu MAX(baz), um die letzte Instanz anstelle der ersten beizubehalten.


0

Dies funktioniert für große Tabellen:

 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;

So löschen Sie die älteste Änderung max(id)anmin(id)


0

Dadurch wird die Spalte column_namezu einem Primärschlüssel und in der Zwischenzeit werden alle Fehler ignoriert. Es werden also die Zeilen mit einem doppelten Wert für gelöscht column_name.

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

Wie in den Kommentaren zur vorherigen Antwort erwähnt, funktioniert dies in 5.7 nicht mehr.
Barmar

0

Ich denke, dies funktioniert, indem die Tabelle im Grunde genommen kopiert und geleert wird und dann nur die unterschiedlichen Werte wieder in die Tabelle eingefügt werden. Bitte überprüfen Sie dies, bevor Sie große Datenmengen verarbeiten.

Erstellt eine Kopie Ihrer Tabelle

Erstellen Sie die Tabelle temp_table wie oldtablename. temp_table einfügen select * from oldtablename;

Leert Ihren Originaltisch

DELETE * von oldtablename;

Kopiert alle unterschiedlichen Werte aus der kopierten Tabelle zurück in Ihre ursprüngliche Tabelle

INSERT oldtablename SELECT * aus der Gruppe temp_table nach Vorname, Nachname, dob

Löscht Ihre temporäre Tabelle.

Löschen Sie die Tabelle temp_table

Sie müssen nach allen Feldern gruppieren, die Sie unterscheiden möchten.


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

Ihre Anfrage funktioniert nicht. Könnten Sie sie bitte verbessern?
Samir Guiderk

0

So eliminiere ich normalerweise Duplikate

  1. füge eine temporäre Spalte hinzu, benenne sie wie du willst (ich werde als aktiv bezeichnen)
  2. Gruppieren Sie nach den Feldern, von denen Sie denken, dass sie nicht doppelt vorhanden sein sollten, und setzen Sie deren Aktiv auf 1. Durch Gruppieren nach wird nur einer der doppelten Werte (keine Duplikate ausgewählt) für diese Spalten ausgewählt
  3. Löschen Sie die mit der aktiven Null
  4. Drop-Spalte aktiv
  5. Fügen Sie optional (falls dies Ihren Zwecken entspricht) einen eindeutigen Index für diese Spalten hinzu, damit keine Duplikate mehr vorhanden sind

-2

Sie können einfach eine DISTINCT-Klausel verwenden, um die "bereinigte" Liste auszuwählen (und hier ist ein sehr einfaches Beispiel dafür).


Wie beantwortet das die Frage? Wenn DISTINCTSie Sie verwenden, verlieren Sie alle Informationen über Duplikate, die Sie möglicherweise überhaupt hatten. Können Sie einen Weg zeigen, um Duplikate damit zu löschen?
luk2302

-3

Könnte es funktionieren, wenn Sie sie zählen und dann Ihrer Löschabfrage ein Limit hinzufügen, so dass nur eines übrig bleibt?

Wenn Sie beispielsweise zwei oder mehr haben, schreiben Sie Ihre Abfrage wie folgt:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

Es gibt nur ein paar grundlegende Schritte, um doppelte Daten aus Ihrer Tabelle zu entfernen:

  • Sichern Sie Ihren Tisch!
  • Suchen Sie die doppelten Zeilen
  • Entfernen Sie die doppelten Zeilen

Hier ist das vollständige Tutorial: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473


Funktioniert es, wenn sich nur die eindeutige ID unterscheidet? Eğer sadece benzersiz id farklı ise de bu işe yarar mı?
Andrew

Standardmäßig funktioniert die hier beschriebene Methode nicht für MySQL-Versionen> 5.7.5. Dies liegt an der Behandlung von ONLY_FULL_GROUP_BY. Siehe hier: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.