2012-04-10 23 views
7

我有如下3列的表格:卸下重複行從表DB2中在單個查詢中

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

該表不具有任何主鍵列。我無法控制表格,所以我無法添加任何主鍵列。

如圖所示,我想刪除一列,兩列和三列的組合相同的行。因此,如果A1B1C1發生三次(如上面的例子),另外兩個應該被刪除,只有一個應該停留。

如何通過DB2中的一個查詢來實現此目的?

我的要求是針對單個查詢,因爲我會通過java程序運行它。

+0

爲什麼你更喜歡{pqr,lmn}以上的xyz和高於def的abc?第一個首選項是按字母順序排列的,第一個是第一個。對我沒有意義。 – wildplasser 2012-04-10 11:24:56

+0

@wildplasser:名稱列在後續步驟中無關緊要。所以沒有這樣的偏好...任何兩個都可以刪除.. – Nik 2012-04-10 11:27:14

回答

17

(這是假設你是在DB2 for Linux的/ UNIX/Windows的,其他平臺可能略有不同)

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

應該給你,你在找什麼。

該查詢使用OLAP functionROWNUMBER()到每個ONETWOTHREE組合內分配一個編號爲每一行。然後,DB2能夠將fullselect(A)引用的行與DELETE statement應從表中刪除的行匹配。爲了能夠使用fullselect作爲刪除子句的目標,它必須符合deletable view的規則(請參閱註釋部分下的「可刪除視圖」)。

下面是一些證據(上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; 

編輯2017年3月2日:

針對艾哈邁德·安華的問題,如果你需要捕獲什麼被刪除,你也可以將刪除與「data change statement」結合起來。在這個例子中,你可以做類似以下,這將使你的「RN」一欄,一個,和:

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

它的工作..但是,請你詳細說明你的答案,並說明究竟發生了什麼... – Nik 2012-04-11 05:21:17

+0

@NikunjChauhan我稍微更新了我的答案,包括一些澄清。 – bhamby 2012-04-11 13:12:17

+0

有沒有辦法使用此查詢來選擇沒有原始記錄的重複項?我試過了,但我對語法不太熟悉,所以我所做的任何更改都會導致錯誤 – 2017-03-01 12:28:19

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) 

您可以使用

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

什麼是id?請詳細說明您的答案。 – Nik 2012-04-10 11:12:29

+0

請再次參考此問題。 – Nik 2012-04-10 11:14:43

+0

您的答案不正確,因爲您使用select查詢構建的表中沒有名稱列。 – Nik 2012-04-10 11:20:28

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

一二threee是你重複列Table_Name_ID是PK

+0

您可以根據需要添加更多列 – levi 2012-04-10 11:12:07

+0

沒有主鍵,我無法控制表中包含的主鍵。 – Nik 2012-04-10 11:13:31

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

注:您的SQL方言可能會有所不同。注2:「名稱」是某些平臺上的保留字。更好地避免它。

+0

但在你的回答中,我們假設zname對每一行都是唯一的。由於表沒有主鍵約束,因此當重複記錄中存在相同的名稱時,此假定將無效。 – Nik 2012-04-10 11:39:54

+0

這是正確的。在這種情況下,你將不得不使用row_number。大多數DMBM都有一個row_number,但名稱因平臺而異。 (row_num,row_id,tid,...)檢查文檔。 – wildplasser 2012-04-10 12:08:22

0

這是levenlevi的答案的變化不需要對錶的主鍵(現在不能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) 

我認爲iSeries上不支持rid_bit(),但rrn()保存相同的用途

1

@a_horse_with_no_name的變體爲iseries回答db2,而不使用group by子句和in子句。它的實際工作

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

對於其他使用非常舊版本的DB2 SQL的:這些職位的組合幫助識別和2批發布兩次刪除複本。

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