it-swarm.com.de

Löschen Sie doppelte Datensätze in PostgreSQL

Ich habe eine Tabelle in einer PostgreSQL 8.3.8-Datenbank, die keine Schlüssel/Einschränkungen enthält und mehrere Zeilen mit genau denselben Werten hat.

Ich möchte alle Duplikate entfernen und nur eine Kopie jeder Zeile behalten.

Es gibt insbesondere eine Spalte ("Schlüssel" genannt), die zur Identifizierung von Duplikaten verwendet werden kann (d. H. Es sollte nur einen Eintrag für jeden einzelnen "Schlüssel" vorhanden sein).

Wie kann ich das machen? (idealerweise mit einem einzigen SQL-Befehl) Geschwindigkeit ist in diesem Fall kein Problem (es gibt nur wenige Zeilen).

74
André Morujão
DELETE FROM dupes a
WHERE a.ctid <> (SELECT min(b.ctid)
                 FROM   dupes b
                 WHERE  a.key = b.key);
56

Eine schnellere Lösung ist

DELETE FROM dups a USING (
      SELECT MIN(ctid) as ctid, key
        FROM dups 
        GROUP BY key HAVING COUNT(*) > 1
      ) b
      WHERE a.key = b.key 
      AND a.ctid <> b.ctid
115
rapimo

Das geht schnell und prägnant:

DELETE FROM dupes T1
    USING   dupes T2
WHERE   T1.ctid < T2.ctid  -- delete the older versions
    AND T1.key  = T2.key;  -- add more columns if needed

Siehe auch meine Antwort unter So löschen Sie doppelte Zeilen ohne eindeutige Kennung die mehr Informationen enthält.

28
isapir

Ich habe das versucht:

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

bereitgestellt von Postgres Wiki:

https://wiki.postgresql.org/wiki/Deleting_duplicates

13
Radu Gabriel

Ich musste meine eigene Version erstellen. Die von @a_horse_with_no_name geschriebene Version ist in meiner Tabelle (21-Zeilen) viel zu langsam. Und @rapimo löscht Dups einfach nicht.

Hier ist was ich auf PostgreSQL 9.5 verwende

DELETE FROM your_table
WHERE ctid IN (
  SELECT unnest(array_remove(all_ctids, actid))
  FROM (
         SELECT
           min(b.ctid)     AS actid,
           array_agg(ctid) AS all_ctids
         FROM your_table b
         GROUP BY key1, key2, key3, key4
         HAVING count(*) > 1) c);
6
expert

Ich würde eine temporäre Tabelle verwenden:

create table tab_temp as
select distinct f1, f2, f3, fn
  from tab;

Dann löschen Sie tab und benennen Sie tab_temp in tab um.

4

Das hat gut für mich funktioniert. Ich hatte eine Tabelle mit Begriffen, die doppelte Werte enthielt. Eine Abfrage ausgeführt, um eine temporäre Tabelle mit allen doppelten Zeilen aufzufüllen. Dann habe ich die Delete-Anweisung mit diesen IDs in der Temp-Tabelle ausgeführt. value ist die Spalte, die die Duplikate enthielt. 

        CREATE TEMP TABLE dupids AS
        select id from (
                    select value, id, row_number() 
over (partition by value order by value) 
    as rownum from terms
                  ) tmp
                  where rownum >= 2;

delete from [table] where id in (select id from dupids)
0
Beanwah