Ich muss DELETE
Zeilen für die angegebene Seite in einer MySQL
Tabelle 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.
Ich muss DELETE
Zeilen für die angegebene Seite in einer MySQL
Tabelle 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.
Antworten:
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
ALTER IGNORE
.
ALTER TABLE foo ENGINE MyISAM
los, um es zu umgehen, und wechselte danach den Motor zurück.
Angenommen, Sie haben eine Tabelle employee
mit den folgenden Spalten:
employee (first_name, last_name, start_date)
So löschen Sie die Zeilen mit einer doppelten first_name
Spalte:
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
employee
sich 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 unique
und dann JOIN
zu einer exakten Übereinstimmung von ID
zu MAX(ID)
?
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_table
es 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
)
SELECT * FROM table GROUP BY title, SID;
Es hängt alles davon ab, wie gut Sie wissen, was Sie tun.
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.
Sie haben keine timestamp
oder 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.
ID
Spalte für das automatische Inkrementieren enthält , muss die ON
Klausel nur mit der ID
Spalte übereinstimmen , sonst nichts.
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.
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 IGNORE
der 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.
ORDER BY
in der brauchen SELECT
, um sicher zu sein, welche Platte es tatsächlich in die schafft NoDupeTable
?
ORDER by ID Asc
konnte es nicht schaden, also werde ich meine Antwort trotzdem bearbeiten.
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.
MAX(ID)
oder MIN(ID)
und Spaltennamen anstatt *
in der SELECT FROM DupeTable
obwohl, sonst erhalten Sie nur einen der ID
zufällig. Tatsächlich erfordern viele SQLs und sogar MySQL strict das Aufrufen einer Aggregatfunktion für jede Spalte, die nicht in der GROUP BY
Klausel angegeben ist.
ID,First,Last,Notes
und Datensätzen hätte 1,Bob,Smith,NULL
und 2,Bob,Smith,Arrears
dann a ausführen SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
würde, würden beide denselben Datensatz 1 zurückgeben, außer mit einer anderen ID. Max (ID) würde zurückkehren 2,Bob,Smith,NULL
und 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.
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;
and a.id_field = b.id
LEFT JOIN
to muss b
nur verglichen werden b.id
= a.id_field
vorausgesetzt, es field_id
handelt sich um eine eindeutige automatische Inkrement-ID. so a.field_being_repeated = b.field_being_repeated
ist irrelevant. (existiert auch b.id_field
nicht in dieser Abfrage, es ist b.id
.
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.
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;
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.
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);
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`;
unique
Spalte 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.
unique
Beachten 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.
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;
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 okay
wenn 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.
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)
Dadurch 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 gelöscht column_name
.
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
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.
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
So eliminiere ich normalerweise Duplikate
Sie können einfach eine DISTINCT-Klausel verwenden, um die "bereinigte" Liste auszuwählen (und hier ist ein sehr einfaches Beispiel dafür).
DISTINCT
Sie 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?
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;
Es gibt nur ein paar grundlegende Schritte, um doppelte Daten aus Ihrer Tabelle zu entfernen:
Hier ist das vollständige Tutorial: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473