2012-04-10 4 views
7

Ich habe eine Tabelle mit 3 Spalten wie folgt:Entfernen von doppelten Zeilen aus einer Tabelle in DB2 in einer einzigen Abfrage

one | two | three | name 
------------------------------------ 
A1  B1   C1  xyz 
A1  B1   C1  pqr  -> should be deleted 
A1  B1   C1  lmn  -> should be deleted 
A2  B2   C2  abc 
A2  B2   C2  def  -> should be deleted 
A3  B3   C3  ghi 
------------------------------------ 

Die Tabelle keine Primärschlüsselspalte aufweist. Ich habe keine Kontrolle über die Tabelle und kann daher keine Primärschlüsselspalte hinzufügen.

Wie gezeigt, möchte ich die Zeilen löschen, in denen die Kombination von einer, zwei und drei Spalte identisch ist. Wenn also A1B1C1 dreimal auftritt (wie beispielsweise oben), sollten die anderen zwei gelöscht werden, und nur einer sollte bleiben.

Wie erreichen Sie dies durch nur eine Abfrage in DB2?

Meine Anforderung ist für eine einzelne Abfrage, wie ich es durch ein Java-Programm ausführen würde.

+0

Warum bevorzugen Sie xyz über {pqr, lmn} und abc über def? Die erste Präferenz ist zuerst alphabetisch sortiert, die zweite zuerst. macht keinen Sinn für mich. – wildplasser

+0

@WildPlasser: Name Spalte spielt keine Rolle in weiteren Schritten. Also gibt es keine solche Präferenz ... jede zwei könnte gelöscht werden. – Nik

Antwort

17

(Dies setzt voraus, Sie auf DB2 sind für Linux/Unix/Windows anderen Plattformen können leicht variieren)

DELETE FROM 
    (SELECT ROWNUMBER() OVER (PARTITION BY ONE, TWO, THREE) AS RN 
    FROM SESSION.TEST) AS A 
WHERE RN > 1; 

Sollten Sie bekommen, was Sie suchen.

Die Abfrage verwendet die OLAP functionROWNUMBER() innerhalb jeder ONE, TWO, THREE Kombination eine Reihe für jede Reihe zuzuordnen. DB2 ist dann in der Lage, die von fullselect (A) referenzierten Zeilen den Zeilen zuzuordnen, die DELETE statement aus der Tabelle entfernen sollte. Um eine fullselect als Ziel für eine Löschklausel verwenden zu können, muss sie den Regeln für eine deletable view entsprechen (siehe "löschbare Ansicht" im Abschnitt "Hinweise").

Unten finden Sie einige Beweise (getestet auf LUW 9.7):

DECLARE GLOBAL TEMPORARY TABLE SESSION.TEST (
    one CHAR(2), 
    two CHAR(2), 
    three CHAR(2), 
    name CHAR(3) 
) ON COMMIT PRESERVE ROWS; 

INSERT INTO SESSION.TEST VALUES 
    ('A1', 'B1', 'C1', 'xyz'), 
    ('A1', 'B1', 'C1', 'pqr'), 
    ('A1', 'B1', 'C1', 'lmn'), 
    ('A2', 'B2', 'C2', 'abc'), 
    ('A2', 'B2', 'C2', 'def'), 
    ('A3', 'B3', 'C3', 'ghi'); 

DELETE FROM 
    (SELECT ROWNUMBER() OVER (PARTITION BY ONE, TWO, THREE) AS RN 
    FROM SESSION.TEST) AS A 
WHERE RN > 1; 

SELECT * FROM SESSION.TEST; 

bearbeiten 2. März 2017:

Als Antwort auf die Frage von Ahmed Anwar, müssen, wenn Sie erfassen, was gelöscht wurde, können Sie kann das Löschen auch mit einem "data change statement" kombinieren.In diesem Beispiel könnten Sie so etwas wie die folgenden tun, mit dem Sie die „rn“ Spalte, ein, zwei und dreigeben würde:

SELECT * FROM OLD TABLE (
    DELETE FROM 
     (SELECT 
      ROWNUMBER() OVER (PARTITION BY ONE, TWO, THREE) AS RN 
      ,ONE 
      ,TWO 
      ,THREE 
     FROM SESSION.TEST) AS A 
    WHERE RN > 1 
) OLD; 
+0

Seine Arbeit .. Könnten Sie bitte bitte Ihre Antwort mit einer kleinen Erklärung, was genau passiert ist ... – Nik

+0

@NikunjChauhan Ich habe meine Antwort ein wenig aktualisiert, um einige Klarstellungen enthalten. – bhamby

+0

Gibt es eine Möglichkeit, diese Abfrage zu verwenden, um die Duplikate ohne den ursprünglichen Datensatz auszuwählen? Ich habe versucht, aber ich bin nicht so vertraut mit der Syntax, so dass alle Änderungen, die ich mache Fehler –

0
Please take backup of table before deleting the data 

Delete from table where Name in (select name from table 
group by one,two,three 
having count(*) > 2) 

können Sie

 DELETE from TABLE Group by one,two,three Having count(*) > 2; 
+0

Was ist ID ?? Bitte erläutern Sie Ihre Antwort. – Nik

+0

Bitte lesen Sie die Frage erneut. – Nik

+0

Ihre Antwort ist falsch, da in der Tabelle, die Sie mit der Select-Abfrage erstellt haben, keine Namensspalte vorhanden ist. – Nik

0
DELETE FROM Table_Name 
WHERE Table_Name_ID NOT IN (SELECT MAX(Table_Name_ID) 
            FROM Table_Name 
            GROUP BY one , 
              two, 
              three) 

ein zwei threee verwenden Ihre wiederholten Spalten und Table_Name_ID ist PK

+0

Sie können so viele Spalten hinzufügen, wie Sie in der Gruppe benötigen – levi

+0

Es gibt keinen Primärschlüssel und ich habe keine Kontrolle über die Tabelle, um einen einzuschließen. – Nik

2
DELETE FROM the_table tt 
WHERE EXISTS (SELECT * 
    FROM the_table ex 
    WHERE ex.one = tt.one 
    AND ex.two = tt.two 
    AND ex.three = tt.three 
    AND ex.zname < tt.zname -- tie-breaker... 
    ); 

Hinweise: Ihre SQL-Dialekt kann variieren. Anmerkung2: "Name" ist ein reserviertes Wort auf einigen Plattformen. Vermeide es besser.

+0

Aber in Ihrer Antwort nehmen wir an, dass zname für jede Zeile eindeutig wäre. Da die Tabelle keine Primärschlüsseleinschränkung aufweist, wäre diese Annahme ungültig, wenn derselbe Name in doppelten Datensätzen vorhanden wäre. – Nik

+0

Das ist richtig. In diesem Fall müssen Sie eine Zeilennummer verwenden. Die meisten DMBMs haben eine Zeilennummer, der Name variiert jedoch zwischen den Plattformen. (row_num, row_id, tid, ...) Überprüfen Sie die Dokumentation. – wildplasser

0

Dies ist eine Variation von levenlevi Antwort dass kein Primärschlüssel auf dem Tisch benötigen (kann nicht die Syntax testen jetzt thow)

DELETE FROM the_table 
WHERE rid_bit(the_table) NOT IN (SELECT MAX(rid_bit(the_table)) 
            FROM the_table 
            GROUP BY one,two,three) 

ich auf iSeries denke, die rid_bit() wird nicht unterstützt, sondern 0.123.Speichern Sie den gleichen Zweck

1

eine Variante von @a_horse_with_no_name Antwort db2 für iseries ohne Verwendung von Group by-Klausel und in-Klausel. Es funktioniert tatsächlich

DELETE from the_table a 
where rrn(a) < (
select max(rrn(a)) from the_table b 
where a.one = b.one and a.two = b.two and a.three = b.three 
) 
0

Für andere eine sehr alte Version von DB2 mit SQL: Eine Kombination dieser Beiträge geholfen zu identifizieren und die dups von 2 Chargen entfernen zweimal gebucht.

SELECT * FROM  LIBRARY.TABLE a 
WHERE a.batch in (115131, 115287) 
AND  EXISTS (SELECT 1 from LIBRARY.TABLE d 
    WHERE d.batch in (115131, 115287) 
    AND a.one = d.one AND a.two = d.two AND a.three = d.three 
    GROUP BY d.one, d.two, d.three 
    HAVING count(*) <> 1) 

    AND RRN(a) > (SELECT MIN(RRN(b)) FROM LIBRARY.TABLE b 
     WHERE b.batch in (115131, 115287) 
     AND a.one = b.one AND a.two = b.two AND a.three = b.three);