Entfernen Sie doppelte Zeilen in MySQL


375

Ich habe eine Tabelle mit folgenden Feldern:

id (Unique)
url (Unique)
title
company
site_id

Jetzt muss ich Zeilen mit demselben entfernen title, company and site_id. Eine Möglichkeit besteht darin, das folgende SQL zusammen mit einem Skript ( PHP) zu verwenden:

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

Nach dem Ausführen dieser Abfrage kann ich Duplikate mithilfe eines serverseitigen Skripts entfernen.

Ich möchte jedoch wissen, ob dies nur mit einer SQL-Abfrage möglich ist.


1
Kurze Frage: Möchten Sie immer, dass kein Duplikat (Titel, Firma, Site-ID) vorhanden ist? In diesem Fall würde ich eine Einschränkung in der Datenbank einrichten, um zu erzwingen, dass Titel, Firma und Site-ID eindeutig sind. Was bedeuten würde, dass Sie keinen Bereinigungsprozess benötigen würden. Und es dauert nur eine einzige Zeile SQL.
J. Polfer

1
Bitte verweisen Sie auf diesen Link von Stackoverflow. Es hat für mich als Zauber funktioniert.

Ich kann diese Lösung empfehlen (veröffentlicht in einem anderen Thread): stackoverflow.com/a/4685232/195835
Simon East

Sie können auch diese Antwort
Jose Rui Santos

Antworten:


607

Eine wirklich einfache Möglichkeit, dies zu tun, besteht darin, einen UNIQUEIndex für die 3 Spalten hinzuzufügen . Geben Sie beim Schreiben der ALTERAnweisung das IGNORESchlüsselwort an. Wie so:

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

Dadurch werden alle doppelten Zeilen gelöscht. Als zusätzlichen Vorteil werden zukünftige INSERTsDuplikate fehlerhaft sein. Wie immer möchten Sie möglicherweise ein Backup erstellen, bevor Sie so etwas ausführen ...


8
Interessant , aber die Annahmen, die die IGNORE-Klausel zum Entfernen dieser Duplikate trifft, sind ein Problem, das möglicherweise nicht den Anforderungen entspricht. Falsche Werte, die auf die nächstgelegene akzeptable Übereinstimmung abgeschnitten werden, klingen für Sie gut?
OMG Ponys

75
Nur für die Aufzeichnung, wenn Sie InnoDB verwenden, dann haben Sie möglicherweise ein Problem damit, es gibt einen bekannten Fehler bei der Verwendung von ALTER IGNORE TABLE mit InnoDB-Datenbanken.
DarkMantis


42
Für InnoDB-Tabellen führen Sie zuerst die folgende Abfrage aus:set session old_alter_table=1;
schock_one


180

Wenn Sie die Spalteneigenschaften nicht ändern möchten, können Sie die folgende Abfrage verwenden.

Da Sie eine Spalte mit eindeutigen IDs haben (z. B. auto_incrementSpalten), können Sie damit die Duplikate entfernen:

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

In MySQL können Sie es mit dem NULL-sicheren Gleichheitsoperator (auch bekannt als "Raumschiffoperator" ) noch weiter vereinfachen :

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
Diese Lösung funktioniert nicht richtig. Ich habe versucht, einige doppelte Datensätze zu erstellen. Sie funktioniert wie folgt (20 Zeilen betroffen). Wenn Sie sie jedoch erneut ausführen, werden sie angezeigt (4 Zeilen betroffen) und so weiter, bis Sie erreichen (0 Zeilen betroffen). Das ist ein bisschen verdächtig und hier ist, was für mich am besten funktioniert, es ist fast das gleiche, aber es funktioniert in einem Durchgang. Ich habe die Lösung bearbeitet
Nassim

1
@Nassim: Sie müssen etwas anderes als diese Antwort tun, weil es für mich perfekt funktioniert (in MySQL).
Lawrence Dol

3
Für alle, die wie ich verwirrt waren, werden die NULL-Vergleichsbegriffe benötigt, da NULL in MySQL nicht gleich NULL ist. Wenn die relevanten Spalten garantiert nicht NULL sind, können Sie diese Begriffe weglassen.
Ian

3
Ja, die akzeptierte Antwort ist nicht mehr gültig, da MYSQL 5.7 also wirklich die akzeptierte Antwort sein sollte, da sie universell ist und auch keine temporäre Tabellenerstellung erfordert.
That-Ben

1
SEHR LANGSAM, wenn es VIELE Kopien eines bestimmten Datensatzes gibt (z. B. 100, die auf 1 reduziert werden sollen), und viele Datensätze mit dieser Bedingung. Empfehlen Sie stattdessen stackoverflow.com/a/4685232/199364 . IMHO, verwenden Sie immer den verknüpften Ansatz; Es ist eine von Natur aus schnellere Technik.
ToolmakerSteve

78

MySQL hat Einschränkungen hinsichtlich des Verweises auf die Tabelle, aus der Sie löschen. Sie können dies mit einer temporären Tabelle umgehen, z. B.:

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

Aus Kostanos 'Vorschlag in den Kommentaren:
Die einzige langsame Abfrage oben ist LÖSCHEN für Fälle, in denen Sie eine sehr große Datenbank haben. Diese Abfrage könnte schneller sein:

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

3
@andomar, dies funktioniert einwandfrei, außer wenn eines der Felder in der where-Klausel Nullen enthält. Beispiel: sqlfiddle.com/#!2/983f3/1
ein Codierer

1
Ist das Insert SQL teuer? Ich frage mich, weil es in meiner MySQL-Datenbank eine Zeitüberschreitung gibt.
Cassio

4
Die einzige langsame Abfrage hier ist die DELETE-Abfrage, falls Sie eine große Datenbank haben. Diese Abfrage könnte schneller sein:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos

@Kostanos Nicht nur DELETE, sondern auch INSERTzum temporären Tisch, es hat lange gedauert . Ein Index für die tmp-Tabelle könnte also create index tmpTable_id_index on tmpTable (id)zumindest für mich sehr hilfreich sein.
Jiezhi.G

1
Wenn Ihre Tabellen groß sind, lohnt es sich, einen Index hinzuzufügen mit: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke

44

Wenn die IGNOREAnweisung nicht wie in meinem Fall funktioniert, können Sie die folgende Anweisung verwenden:

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
funktioniert hervorragend, wenn Sie eine innoDB-Einstellung mit Fremdschlüsseleinschränkung haben.
Magdmartin

@magdmartin, aber verhindern ausländische Einschränkungen nicht das Löschen von Tabellen?
Basilevs

1
Die IGNORE-Anweisung hat bei mir nicht funktioniert, und dies hat bei der Bereitstellung von 5 Millionen Datensätzen hervorragend funktioniert. Prost.
Mauvis Ledford

32

Das Löschen von Duplikaten in MySQL-Tabellen ist ein häufiges Problem. Dies ist im Allgemeinen das Ergebnis einer fehlenden Einschränkung, um diese Duplikate vorab zu vermeiden. Dieses häufig auftretende Problem ist jedoch in der Regel mit spezifischen Anforderungen verbunden, die bestimmte Ansätze erfordern. Der Ansatz sollte unterschiedlich sein, abhängig beispielsweise von der Größe der Daten, dem doppelten Eintrag, der beibehalten werden soll (im Allgemeinen der erste oder der letzte), ob Indizes beibehalten werden müssen oder ob zusätzliche Änderungen vorgenommen werden sollen Aktion auf die duplizierten Daten.

Es gibt auch einige Besonderheiten in MySQL selbst, z. B., dass beim Ausführen eines Tabellen-UPDATE nicht auf dieselbe Tabelle in einer FROM-Ursache verwiesen werden kann (dies führt zu MySQL-Fehler Nr. 1093). Diese Einschränkung kann überwunden werden, indem eine innere Abfrage mit einer temporären Tabelle verwendet wird (wie bei einigen Ansätzen oben vorgeschlagen). Diese innere Abfrage funktioniert jedoch beim Umgang mit Big-Data-Quellen nicht besonders gut.

Es gibt jedoch einen besseren Ansatz zum Entfernen von Duplikaten, der sowohl effizient als auch zuverlässig ist und leicht an unterschiedliche Anforderungen angepasst werden kann.

Die allgemeine Idee besteht darin, eine neue temporäre Tabelle zu erstellen, in der Regel eine eindeutige Einschränkung hinzuzufügen, um weitere Duplikate zu vermeiden, und die Daten aus Ihrer früheren Tabelle in die neue einzufügen, während Sie sich um die Duplikate kümmern. Dieser Ansatz basiert auf einfachen MySQL INSERT-Abfragen, erstellt eine neue Einschränkung, um weitere Duplikate zu vermeiden, und überspringt die Verwendung einer inneren Abfrage zur Suche nach Duplikaten und einer temporären Tabelle, die im Speicher aufbewahrt werden sollte (wodurch auch große Datenquellen angepasst werden).

So kann es erreicht werden. Gegeben wir einen Tisch haben Mitarbeiter , mit den folgenden Spalten:

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

Um die Zeilen mit einer doppelten SSN- Spalte zu löschen und nur den ersten gefundenen Eintrag beizubehalten , kann der folgende Vorgang ausgeführt werden:

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

Technische Erklärung

  • Linie # 1 erstellt eine neue tmp_eployee Tabelle mit genau der gleichen Struktur wie die Mitarbeiter Tabelle
  • Zeile 2 fügt der neuen Tabelle tmp_eployee eine EINZIGARTIGE Einschränkung hinzu , um weitere Duplikate zu vermeiden
  • Zeile 3 durchsucht die ursprüngliche Mitarbeitertabelle nach ihrer ID, fügt neue Mitarbeitereinträge in die neue Tabelle tmp_eployee ein und ignoriert doppelte Einträge
  • In Zeile 4 werden Tabellen umbenannt, sodass die neue Mitarbeitertabelle alle Einträge ohne die Duplikate enthält und eine Sicherungskopie der früheren Daten in der Tabelle backup_employee gespeichert wird

Mit diesem Ansatz wurden 1,6 Millionen Register in weniger als 200 Sekunden in 6 KB konvertiert.

Chetan : Nach diesem Vorgang können Sie schnell und einfach alle Ihre Duplikate entfernen und eine EINZIGARTIGE Einschränkung erstellen, indem Sie Folgendes ausführen:

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;

Natürlich kann dieser Prozess weiter modifiziert werden, um ihn beim Löschen von Duplikaten an unterschiedliche Anforderungen anzupassen. Es folgen einige Beispiele.

✔ Variation zum Beibehalten des letzten Eintrags anstelle des ersten

Manchmal müssen wir den letzten duplizierten Eintrag anstelle des ersten behalten.

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;
  • In Zeile 3 bewirkt die ORCER BY id DESC- Klausel, dass die letzten IDs Vorrang vor den anderen haben

✔ Variation zum Ausführen einiger Aufgaben für die Duplikate, z. B. Zählen der gefundenen Duplikate

Manchmal müssen wir die gefundenen duplizierten Einträge weiter verarbeiten (z. B. die Anzahl der duplizierten Einträge beibehalten).

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;
  • In Zeile 3 wird eine neue Spalte n_duplicates erstellt
  • In Zeile 4 wird die Abfrage INSERT INTO ... ON DUPLICATE KEY UPDATE verwendet, um eine zusätzliche Aktualisierung durchzuführen, wenn ein Duplikat gefunden wird (in diesem Fall wird ein Zähler erhöht). Die Abfrage INSERT INTO ... ON DUPLICATE KEY UPDATE kann sein wird verwendet, um verschiedene Arten von Aktualisierungen für die gefundenen Duplikate durchzuführen.

✔ Variation zum Regenerieren der automatisch inkrementellen Feld-ID

Manchmal verwenden wir ein automatisch inkrementelles Feld. Um den Index so kompakt wie möglich zu halten, können wir das Löschen der Duplikate nutzen, um das automatisch inkrementelle Feld in der neuen temporären Tabelle neu zu generieren.

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;
  • In Zeile 3 wird das ID-Feld übersprungen, anstatt alle Felder in der Tabelle auszuwählen, sodass die DB-Engine automatisch ein neues generiert

✔ Weitere Variationen

Abhängig vom gewünschten Verhalten sind auch viele weitere Modifikationen möglich. In den folgenden Abfragen wird beispielsweise eine zweite temporäre Tabelle verwendet, um neben 1) den letzten Eintrag anstelle des ersten zu behalten; und 2) einen Zähler für die gefundenen Duplikate erhöhen; auch 3) Generieren Sie die automatisch inkrementelle Feld-ID neu, während Sie die Eingabereihenfolge wie bei den vorherigen Daten beibehalten.

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

Es gibt noch eine andere Lösung:

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
Wie unterscheidet sich das von der Antwort von @ rehriff, die er 6 Monate zuvor eingereicht hat?
Lawrence Dol

@LawrenceDol Ich denke, es ist ein bisschen besser lesbar und ich denke auch, dass seine Antwort zum Zeitpunkt meiner Antwort nicht dieselbe war und ich denke, dass seine Antwort bearbeitet wurde.
Mostafa -T

1
hmm. Es dauert zu lange für mich, während die Anzahl der Datensätze nicht groß war!
SuB

8

Wenn Sie eine große Tabelle mit einer großen Anzahl von Datensätzen haben, funktionieren die oben genannten Lösungen nicht oder nehmen zu viel Zeit in Anspruch. Dann haben wir eine andere Lösung

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

Ich habe dieses Abfrage-Snipet für SQLServer, aber ich denke, es kann mit kleinen Änderungen in anderen DBMS verwendet werden:

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

Ich habe vergessen, Ihnen mitzuteilen, dass diese Abfrage die Zeile mit der niedrigsten ID der duplizierten Zeilen nicht entfernt. Wenn dies für Sie funktioniert, versuchen Sie diese Abfrage:

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

Das funktioniert nicht, wenn mehr als zwei Duplikate einer Gruppe vorhanden sind.
OMG Ponys

11
Leider erlaubt MySQL nicht, aus der Tabelle auszuwählen, aus der Sie löschenERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar

1
"You can't specify target table 'Table' for update in FROM..."Verwenden Sie DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1):, um MySQL zu zwingen, eine temporäre Tabelle zu erstellen, um den Fehler zu beheben. In großen Datenmengen ist es jedoch sehr langsam. In solchen Fällen empfehle ich den Code von Andomar, der viel schneller ist.
Lepe

6

Der schnellere Weg besteht darin, bestimmte Zeilen in eine temporäre Tabelle einzufügen. Mit delete habe ich einige Stunden gebraucht, um Duplikate aus einer Tabelle mit 8 Millionen Zeilen zu entfernen. Mit Insert und Different dauerte es nur 13 Minuten.

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
Ihre 4. Zeile sollte sagen TRUNCATE TABLE tableNameund 5. Zeile sollte sagenINSERT INTO tableName SELECT * FROM tempTableName;
Sana

5

Eine Lösung, die einfach zu verstehen ist und ohne Primärschlüssel funktioniert:

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) Lassen Sie die hinzugefügte Spalte fallen

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.


1
Dies funktionierte wirklich gut in MySQL 5.7, wo akzeptierte Lösung nicht mehr funktioniert
Robin31

5

Löschen doppelter Zeilen mit der Anweisung DELETE JOIN MySQL stellt Ihnen die Anweisung DELETE JOIN zur Verfügung, mit der Sie doppelte Zeilen schnell entfernen können.

Die folgende Anweisung löscht doppelte Zeilen und behält die höchste ID bei:

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

5

Ich habe einen einfachen Weg gefunden. (auf dem neuesten Stand halten)

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

Einfach und schnell für alle Fälle:

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

Fehlercode: 1055. Ausdruck Nr. 2 der SELECT-Liste befindet sich nicht in der GROUP BY-Klausel und enthält die nicht aggregierte Spalte 'dub.id', die funktional nicht von den Spalten in der GROUP BY-Klausel abhängig ist. Dies ist nicht kompatibel mit sql_mode = only_full_group_by
Swoogan

Sie könnten "harte Kontrolle" mit sql_mode deaktivieren, siehe stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz

4

Dadurch werden die doppelten Zeilen mit denselben Werten für Titel, Firma und Site gelöscht. Das erste Vorkommen wird beibehalten und alle Duplikate werden gelöscht

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;

es ist langsam (5w + Reihen, Wartezeit sperren) aber es hat funktioniert
yurenchen

3

Ich besuche diese Seite immer dann, wenn ich "Duplikate aus MySQL entfernen" google, aber für meine theIGNORE-Lösungen funktioniert dies nicht, da ich eine InnoDB-MySQL-Tabelle habe

Dieser Code funktioniert jederzeit besser

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 = Der Name der Tabelle, die Sie bereinigen müssen

tableToclean_temp = Eine temporäre Tabelle, die erstellt und gelöscht wurde


2

Diese Lösung verschiebt die Duplikate in eine Tabelle und die Unikate in eine andere .

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

Warum hast du die Gewerkschaft übernommen und nicht nur SELECT * FROM jobs GROUP BY site_id, company, title, location?
Timctran

2

Ab Version 8.0 (2018) unterstützt MySQL endlich Fensterfunktionen .

Fensterfunktionen sind sowohl praktisch als auch effizient. Hier ist eine Lösung, die zeigt, wie Sie diese Aufgabe lösen können.

In einer Unterabfrage können wir ROW_NUMBER()jedem Datensatz in der Tabelle innerhalb von column1/column2Gruppen eine Position zuweisen , geordnet nach id. Wenn keine Duplikate vorhanden sind, erhält der Datensatz die Zeilennummer 1. Wenn ein Duplikat vorhanden ist, werden diese durch Aufsteigen id(beginnend mit 1) nummeriert .

Sobald die Datensätze in der Unterabfrage ordnungsgemäß nummeriert sind, löscht die äußere Abfrage nur alle Datensätze, deren Zeilennummer nicht 1 ist.

Abfrage:

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

So löschen Sie den doppelten Datensatz in einer Tabelle.

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

oder

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

Um Datensätze mit eindeutigen Spalten zu duplizieren, z. B. COL1, COL2, sollte COL3 nicht repliziert werden (Angenommen, wir haben 3 in der Tabellenstruktur eindeutige Spalten übersehen und mehrere doppelte Einträge in die Tabelle vorgenommen).

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;

Hoffnung wird dev helfen.


0

TL; TR;

Ein ausführlich beschriebenes Tutorial zur Lösung dieses Problems finden Sie auf der Website mysqltutorial.org :

So löschen Sie doppelte Zeilen in MySQL

Es wird sehr deutlich gezeigt, wie doppelte Zeilen auf drei verschiedene Arten gelöscht werden :

A) Mit DELETE JOINAussage

B) Verwenden einer Zwischentabelle

C) Unter Verwendung ROW_NUMBER()Funktion

Ich hoffe, dass es jemandem helfen wird.


0

Ich habe eine Tabelle, die vergisst, einen Primärschlüssel in die ID-Zeile einzufügen. Allerdings hat die ID auto_increment. Aber eines Tages wird das MySQL-Bin-Protokoll in der Datenbank wiederholt, wobei einige doppelte Zeilen eingefügt werden.

Ich entferne die doppelte Zeile durch

  1. Wählen Sie die eindeutigen doppelten Zeilen aus und exportieren Sie sie

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. Löschen Sie die doppelten Zeilen nach ID

  2. Fügen Sie die Zeile aus den exportierten Daten ein.

  3. Fügen Sie dann den Primärschlüssel auf id hinzu


-2

Ich möchte etwas genauer sagen, welche Datensätze ich lösche. Hier ist meine Lösung:

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

Sie können die doppelten Datensätze einfach aus diesem Code löschen.

$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
Dies ist eine sehr schlechte Form - Datenbankaufgaben sollten in der Datenbank ausgeführt werden, wo sie viel schneller sind, anstatt ständig Daten zwischen PHP / MySQL zu senden, da Sie eine besser kennen als die andere.
Max

-4

Ich musste dies mit Textfeldern tun und stieß auf die Grenze von 100 Bytes im Index.

Ich habe dieses Problem gelöst, indem ich eine Spalte hinzugefügt, einen MD5-Hash der Felder erstellt und die Änderung vorgenommen habe.

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