it-swarm.com.de

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

Ich muss DELETE duplizierte Zeilen für die angegebene Sid in einerMySQLTabelle haben.

Wie kann ich dies mit einer SQL-Abfrage machen?

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

So etwas, aber ich weiß nicht, wie es geht.

139
Ali Poder

dadurch werden Duplikate an Ort und Stelle entfernt, ohne eine neue Tabelle erstellen zu müssen

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

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

199
user187291

Angenommen, Sie haben eine Tabelle employee mit den folgenden Spalten:

employee (first_name, last_name, start_date)

Um die Zeilen mit einer doppelten Spalte first_name zu löschen:

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

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

Mit Temp-Tisch

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

DROP TABLE table;
RENAME TABLE table_temp TO table;

Da temp_table neu erstellt wurde, gibt es keine Indizes. Sie müssen sie nach dem Entfernen von Duplikaten neu erstellen. Mit SHOW INDEXES IN table können Sie überprüfen, welche Indizes Sie in der Tabelle haben.

Ohne Tempetisch:

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
)
53
Kamil Szot

Löschen doppelter Zeilen in MySQL, Komplettlösung

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

dev-db> create table penguins(foo int, bar varchar(15), baz datetime);
Query OK, 0 rows affected (0.07 sec)
dev-db> insert into penguins values(1, 'skipper', now());
dev-db> insert into penguins values(1, 'skipper', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(4, 'rico', now());
Query OK, 6 rows affected (0.07 sec)
dev-db> 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)

Dann entferne die Duplikate:

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

Ergebnis:

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

Was macht diese Anweisung zum Löschen

Pseudocode: Gruppieren Sie die Zeilen nach den beiden Spalten, deren Duplikate entfernt werden sollen. Wählen Sie die einzige Zeile jeder Gruppe aus, die Sie behalten möchten, indem Sie das maximale Aggregat verwenden. Ein linker Join gibt alle Zeilen aus der linken Tabelle mit den übereinstimmenden Zeilen in der rechten Tabelle zurück. In diesem Fall enthält die linke Tabelle alle Zeilen in der Tabelle, und die rechte enthält nur die Zeilen, die NULL sind (nicht die einzige Zeile pro Gruppe, die Sie behalten möchten). Wenn Sie diese Zeilen löschen, bleiben nur die eindeutigen Zeilen pro Gruppe übrig.

Weitere technische Erläuterungen, Wie Sie diese SQL-Löschanweisung lesen sollten:

Tischpinguine mit dem Alias ​​'a' bleiben auf einer Teilmenge von Tischpinguinen, Alias ​​'b', verbunden. Die rechte Tabelle 'b', bei der es sich um eine Teilmenge handelt, ermittelt den maximalen Zeitstempel nach foo und bar. Dies ist auf die linke Tabelle "a" abgestimmt. (foo, bar, baz) auf der linken Seite hat jede Zeile in der Tabelle. Die rechte Untergruppe 'b' hat einen Wert (maxtimestamp, foo, bar), der links mit dem Wert übereinstimmt, der IS die max.

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

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

Verhindern Sie, dass dieses Problem in dieser Tabelle erneut auftritt:

Wenn Sie dies zum Laufen gebracht haben, wird Ihr "doppelte Zeilen" -Feuer gelöscht. Großartig. Deine Arbeit ist noch nicht erledigt. Definieren Sie einen neuen zusammengesetzten eindeutigen Schlüssel in Ihrer Tabelle (in diesen beiden Spalten), um zu verhindern, dass zunächst weitere Duplikate hinzugefügt werden. Wie ein gutes Immunsystem sollten die schlechten Reihen zum Zeitpunkt des Einfügens nicht einmal in die Tabelle aufgenommen werden. Später senden alle Programme, die Duplikate hinzufügen, ihren Protest, und wenn Sie sie beheben, wird dieses Problem nie wieder auftauchen.

45
Eric Leschinski

Das scheint für mich immer zu funktionieren:

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

Das behält die niedrigste ID für jedes der Duplikate und den Rest der Nicht-Dupe-Datensätze bei.

Ich habe auch die folgenden Schritte 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 haben möchte, und mache dann einen Insert IGNORE, der den Vorteil hat, dass er nicht als normale Insert beim ersten Versuch ausfällt Sie fügen einen doppelten Datensatz basierend auf den beiden Feldern hinzu und ignorieren solche Datensätze.

Durch das Verschieben von fwd können keine doppelten Datensätze erstellt werden, die auf diesen beiden Feldern basieren.

12
user3649739

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

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

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

Der einzige Nachteil ist, dass ich die Abfrage mehrmals ausführen muss, aber trotzdem fand ich, dass es für mich besser war als die anderen Optionen.

9
seaders

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

Folgendes 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
M.B.Miri

Diese Arbeit für mich, um alte Datensätze 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) bis max (e.id) ersetzen, um die neuesten Datensätze zu entfernen.

5
richardhell

Bei diesem Verfahren werden alle Duplikate (einschließlich Vielfachen) in einer Tabelle entfernt, wobei das letzte Duplikat erhalten bleibt. Dies ist eine Erweiterung von Abrufen des letzten Datensatzes in jeder Gruppe

Hoffe, das ist jemandem nützlich.

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
Simon
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;
3
temonehm

Ein anderer 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 Uniques in, indem Sie sie mit der ignore-Klausel aktualisieren. Schritt für Schritt: 

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

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

=> Dies fügt Ihrer Tabelle eine Spalte hinzu. 

Aktualisieren Sie die Tabelle, versuchen Sie, alles als eindeutig zu kennzeichnen, aber ignorieren Sie mögliche Fehler aufgrund eines doppelten Schlüssels (Datensätze werden übersprungen):

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

=> Sie werden feststellen, dass Ihre doppelten Datensätze nicht als eindeutig gekennzeichnet sind = "Ja", dh, nur ein Satz jedes doppelten Datensatzes wird als eindeutig gekennzeichnet.

Löschen Sie alles, was nicht eindeutig ist:

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

=> Dies entfernt alle doppelten Datensätze.

Lass die Spalte fallen ...

ALTER TABLE `yourtable` DROP `unique`;
2
Werner

Ich finde, dass Werners Lösung oben die bequemste ist, weil sie unabhängig vom Vorhandensein eines Primärschlüssels funktioniert, sich nicht mit Tabellen beschäftigt, zukunftssicheres einfaches SQL verwendet und sehr verständlich ist.

Wie ich in meinem Kommentar feststellte, wurde diese Lösung nicht richtig erklärt ... Das ist also meine, darauf basierend.

1) füge 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 wird aufgrund der neuen Einschränkung nur in einer der duplizierten Zeilen gelingen

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) lassen Sie die hinzugefügte Säule fallen

alter table mytable drop tokeep;

Ich empfehle Ihnen, die von Ihnen hinzugefügte Einschränkung beizubehalten, damit in Zukunft neue Duplikate vermieden werden.

1
xtian

Das Löschen von Duplikaten in MySQL-Tabellen ist ein häufiges Problem, das normalerweise mit besonderen Anforderungen verbunden ist. Falls jemand interessiert ist, erkläre ich hier ( Doppelte Zeilen in MySQL entfernen ). Ich erkläre, wie man mit Hilfe einer temporären Tabelle MySQL-Duplikate zuverlässig und schnell löscht, auch für Big Data-Quellen (mit Beispielen für andere Zwecke) Fä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;
1

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;

Um die älteste Änderung max(id) in min(id) zu löschen

0

Ich denke, dass dies funktionieren wird, indem Sie die Tabelle im Wesentlichen kopieren und leeren. Dann werden nur die verschiedenen Werte wieder in die Tabelle eingefügt.

Erstellt eine Kopie des Tisches

erstellen Sie die Tabelle temp_table wie oldtablename; Einfügen von temp_table select * from oldtablename;

Leert Ihren ursprünglichen Tisch

DELETE * from oldtablename;

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

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

Löscht Ihre temporäre Tabelle.

Tabelle temp_table löschen

Sie müssen nach ALL-Feldern gruppieren, die Sie getrennt halten möchten.

0
ChrisAardvark
DELETE T2
FROM   table_name T1
JOIN   same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
0
Nav
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
)
0
Patrick

Love @ erics Antwort, aber es scheint nicht zu funktionieren, wenn Sie eine wirklich große Tabelle 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 okay, wenn ich versuche, sie auszuführen). Also beschränkte ich mich auf die Join-Abfrage, um nur die doppelten Zeilen zu berücksichtigen, und ich endete mit:

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 erlaubt MySQL in diesem Fall, Zeilen zu ignorieren, die kein Duplikat haben, und auch, wenn dies die erste Instanz des Duplikats ist, so dass sie ignoriert wird. Ändern Sie MIN(baz) in MAX(baz), um die letzte Instanz anstelle der ersten Instanz beizubehalten.

0
Gujamin

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

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