it-swarm.com.de

Wie kann ich eine von zwei vollkommen identischen Reihen löschen?

Ich säubere eine Datenbanktabelle ohne Primärschlüssel (ich weiß, ich weiß, woran sie gedacht haben). Ich kann keinen Primärschlüssel hinzufügen, da in der Spalte ein Duplikat enthalten ist, das zum Schlüssel werden würde. Der doppelte Wert stammt aus einer von zwei Zeilen, die in jeder Hinsicht identisch sind. Ich kann die Zeile nicht über eine grafische Benutzeroberfläche löschen (in diesem Fall MySQL Workbench, aber ich suche nach einem datenbankunabhängigen Ansatz), da sie sich weigert, Tasks ohne Primärschlüssel (oder zumindest eine UQ NN-Spalte) auszuführen Ich kann keinen Primärschlüssel hinzufügen, da in der Spalte ein Duplikat enthalten ist, das zum Schlüssel werden würde. Der doppelte Wert kommt von einem ...

Wie kann ich eine der Zwillinge löschen?

27
d3vid

Eine Möglichkeit, Ihr Problem zu lösen, besteht darin, eine neue Tabelle mit demselben Schema zu erstellen und dann Folgendes auszuführen:

INSERT INTO new_table (SELECT DISTINCT * FROM old_table)

und benennen Sie dann einfach die Tabellen um.

Natürlich benötigen Sie ungefähr so ​​viel Speicherplatz, wie Ihre Tabelle auf Ihrer Festplatte benötigt, um dies zu tun!

Es ist nicht effizient, aber es ist unglaublich einfach.

19
Alnitak
SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0

Dadurch wird nur eine der beiden identischen Zeilen gelöscht

51
Rinaldo

Beachten Sie, dass MySQL seine eigene Erweiterung von DELETE hat. Dies ist DELETE ... LIMIT. Sie funktioniert wie üblich von LIMIT: http://dev.mysql.com/doc/refman/5.0/de/delete.html

Die MySQL-spezifische LIMIT-Option row_count von DELETE teilt dem Server mit Die maximale Anzahl von Zeilen, die gelöscht werden sollen, bevor die Steuerung an .__ zurückgegeben wird. der Kunde. Dies kann verwendet werden, um sicherzustellen, dass eine gegebene DELETE-Anweisung dauert nicht zu viel zeit. Sie können einfach DELETE .__ wiederholen. Anweisung, bis die Anzahl der betroffenen Zeilen kleiner als LIMIT ist Wert.

Daher können Sie DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1; verwenden. Beachten Sie, dass es keine einfache Möglichkeit gibt, "alles außer einem löschen" zu sagen - überprüfen Sie einfach, ob Sie noch Zeilenduplikate haben.

19
Piskvor

Für PostgreSQL können Sie Folgendes tun:

DELETE FROM tablename
WHERE id IN (SELECT id
          FROM (SELECT id, ROW_NUMBER() 
               OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
               FROM tablename) t
          WHERE t.rnum > 1);

spalte1, Spalte2, Spalte3 wäre der Spaltensatz, der doppelte Werte hat.

Referenz hier .

10
Turbut Alin

delete top (1) funktioniert auf Microsoft SQL Server (T-SQL).

5
mattinsalto

Dies kann mithilfe eines CTE und der Funktion ROW_NUMBER() wie folgt durchgeführt werden:

/* Sample Data */
    CREATE TABLE #dupes (ID INT, DWCreated DATETIME2(3))

    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2015-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 2, '2014-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2013-08-03 01:02:03.456'

/* Check sample data - returns three rows, with two rows for ID#1 */
    SELECT * FROM #dupes 

/* CTE to give each row that shares an ID a unique number */
    ;WITH toDelete AS
      (
        SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DWCreated) AS RN
        FROM #dupes 
      )

  /* Delete any row that is not the first instance of an ID */
    DELETE FROM toDelete WHERE RN > 1

/* Check the results: ID is now unique */
    SELECT * FROM #dupes

/* Clean up */
    DROP TABLE #dupes

Eine Spalte zu ORDER BY zu haben ist praktisch, aber nicht notwendig, es sei denn, Sie haben Vorrang vor der zu löschenden Zeile. Dadurch werden auch alle Instanzen von doppelten Datensätzen behandelt, anstatt Sie zu zwingen, jeweils eine Zeile zu löschen. 

4
AHiggins

Versuchte LIMIT 1? Dadurch wird nur eine der Zeilen gelöscht, die Ihrer DELETE-Abfrage entsprechen

DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;
3
Feelsbadman

In meinem Fall würde könnte die GUI dazu bringen, mir eine Reihe von Werten der fraglichen Zeile zu geben (alternativ hätte ich dies auch manuell tun können). Auf Vorschlag eines Kollegen, dessen Schulden ich noch habe, habe ich eine INSERT-Anweisung erstellt:

INSERT
'ID1219243408800307444663', '2004-01-20 10:20:55', 'INFORMATION', 'admin' (...)
INTO some_table;

Ich habe die Einfügung getestet, so dass ich jetzt Drillinge hatte. Zum Schluss habe ich ein einfaches LÖSCHEN ausgeführt, um alle zu entfernen ...

DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';

gefolgt von INSERT noch einmal, sodass ich nur noch eine einzige Zeile habe und die hellen Möglichkeiten eines Primärschlüssels.

1
d3vid

falls Sie eine Spalte hinzufügen möchten

  ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)

tun Sie dies.

zählen Sie dann die Zeilen, die nach Ihrer Problemspalte gruppiert werden, wobei count> 1 ist. Dadurch werden Ihre Zwillinge (oder Drillinge oder was auch immer) identifiziert.

wählen Sie dann Ihre Problemspalte aus, deren Inhalt mit dem oben angegebenen Inhalt übereinstimmt, und überprüfen Sie die IDs in IDCOLUMN. 

löschen Sie aus Ihrer Tabelle, wobei IDCOLUMN einer dieser IDs entspricht.

1
Der U

Dies funktioniert für PostgreSQL

DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)
1
Vlad B

Sie könnten einen max verwenden, der in meinem Fall relevant war.

DELETE FROM [table] where id in 
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)

Stellen Sie sicher, dass Sie Ihre Ergebnisse zuerst testen und eine Begrenzungsbedingung in Ihrem Klausel haben. Bei einer solchen großen Löschabfrage möchten Sie möglicherweise zuerst Ihre Datenbank aktualisieren.

1
TIm

In PostgreSQL gibt es eine implizite Spalte mit dem Namen ctid. Siehe das wiki . Sie können also Folgendes verwenden:

WITH cte1 as(
    SELECT unique_column, max( ctid ) as max_ctid
    FROM table_1
    GROUP BY unique_column
    HAVING count(*) > 1
), cte2 as(
    SELECT t.ctid as target_ctid
    FROM table_1 t
    JOIN cte1 USING( unique_column )
    WHERE t.ctid != max_ctid
)
DELETE FROM table_1
WHERE ctid IN( SELECT target_ctid FROM cte2 )

Ich bin mir nicht sicher, wie sicher es ist, dies zu verwenden, wenn gleichzeitig Aktualisierungen möglich sind. Daher kann es sinnvoll sein, vor der eigentlichen Bereinigung einen LOCK TABLE table_1 IN ACCESS EXCLUSIVE MODE; zu erstellen.

0
volvpavl

Ich habe der Tabelle eine Guid-Spalte hinzugefügt und sie so eingestellt, dass für jede Zeile eine neue ID generiert wird. Dann könnte ich die Zeilen über eine GUI löschen.

0
Ian Warburton

Falls mehrere doppelte Zeilen zu löschen sind und alle Felder identisch sind, keine unterschiedliche ID, die Tabelle hat keinen Primärschlüssel, besteht eine Option darin, die doppelten Zeilen mit distinct in einer neuen Tabelle zu speichern, alle doppelten Zeilen zu löschen und die Zeilen wieder einzufügen . Dies ist hilfreich, wenn die Tabelle sehr groß ist und die Anzahl der doppelten Zeilen gering ist.

---  col1 , col2 ... coln are the table columns that are relevant. 
--- if not sure add all columns of the table in the select bellow and the where clause later. 

--- make a copy of the table T to be sure you can rollback anytime , if possible
--- check the @@rowcount to be sure it's what you want
--- use transactions and rollback in case there is an error 

--- first find all with duplicate rows that are identical , this statement could be joined 
--- with the first one if you choose all columns 

select col1,col2, --- other columns as needed
  count(*) c into temp_duplicate group by col1,col2 having count(*) > 1 

--- save all the rows that are identical only once ( DISTINCT ) 

insert distinct * into temp_insert from T , temp_duplicate D where
T.col1 = D.col1 and
T.col2 = D.col2 --- and other columns if needed

--- delete all the rows that are duplicate

delete T from T , temp_duplicate D where 
T.col1 = D.col1 and
T.col2 = D.col2 ---- and other columns if needed

--- add the duplicate rows , now only once
insert into T select * from temp_insert 

--- drop the temp tables after you check all is ok 
0
detzu