2012-04-10 43 views
7

Tôi có một bảng với 3 cột như sau:Loại bỏ các hàng trùng lặp từ một bảng trong DB2 trong một truy vấn đơn

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

bảng này không được có bất kỳ cột khóa chính. Tôi không có bất kỳ điều khiển nào trên bàn và vì vậy tôi không thể thêm bất kỳ cột khóa chính nào.

Như được hiển thị, tôi muốn xóa các hàng có kết hợp một, hai và ba cột giống nhau. Vì vậy, nếu A1B1C1 xảy ra ba lần (như ở trên ví dụ), hai cái còn lại sẽ bị xóa và chỉ một người nên ở lại.

Làm thế nào để đạt được điều này thông qua chỉ một truy vấn trong DB2?

Yêu cầu của tôi là cho một truy vấn duy nhất vì tôi sẽ chạy nó thông qua một chương trình java.

+0

tại sao bạn thích xyz ở trên {pqr, lmn} và abc trên def? Tùy chọn đầu tiên đầu tiên khi được sắp xếp theo thứ tự bảng chữ cái, thứ hai đầu tiên. không có ý nghĩa với tôi. – wildplasser

+0

@wildplasser: cột tên không quan trọng trong các bước tiếp theo. Vì vậy, không có sở thích như vậy ... bất kỳ hai có thể bị xóa .. – Nik

Trả lời

17

(Điều này giả định bạn đang ở trên DB2 cho Linux/Unix/Windows, hệ điều hành khác có thể thay đổi chút ít)

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

nên giúp bạn có được những gì bạn đang tìm kiếm.

Truy vấn sử dụng OLAP functionROWNUMBER() để gán một số cho mỗi hàng trong mỗi sự kết hợp ONE, TWO, THREE. Sau đó, DB2 có thể khớp các hàng được tham chiếu bởi fullselect (A) như các hàng mà DELETE statement sẽ loại bỏ khỏi bảng. Để có thể sử dụng fullselect làm mục tiêu cho một mệnh đề xóa, nó phải khớp với các quy tắc cho một deletable view (xem "chế độ xem có thể xóa" trong phần ghi chú).

Dưới đây là một số bằng chứng (thử nghiệm trên 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; 

Chỉnh sửa ngày 02 tháng 3 năm 2017:

Để đối phó với các câu hỏi từ Ahmed Anwar, nếu bạn cần phải nắm bắt những gì đã bị xóa, bạn cũng có thể kết hợp xóa với "data change statement".Trong ví dụ này, bạn có thể làm điều gì đó như sau, trong đó sẽ cung cấp cho bạn "rn" cột, một, hai, và ba:

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

Tuy nhiên, làm việc của nó, bạn có thể vui lòng xây dựng câu trả lời của bạn với một chút giải thích về những gì chính xác đang diễn ra không? – Nik

+0

@NikunjChauhan Tôi đã cập nhật câu trả lời của mình một chút để bao gồm một số làm rõ. – bhamby

+0

Có cách nào để sử dụng truy vấn này để CHỌN các bản sao không có bản ghi gốc không? Tôi đã thử nhưng tôi không quá quen thuộc với cú pháp vì vậy bất kỳ thay đổi nào mà tôi tạo ra đều có lỗi –

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) 

Bạn có thể sử dụng

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

id là gì ?? Hãy xây dựng câu trả lời của bạn. – Nik

+0

Vui lòng tham khảo lại câu hỏi. – Nik

+0

Câu trả lời của bạn không chính xác vì không có cột tên trong bảng bạn đã tạo bằng truy vấn chọn. – 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) 

một hai threee được cột lặp đi lặp lại của bạn và Table_Name_ID là PK

+0

bạn có thể thêm nhiều cột hơn nếu bạn cần theo nhóm theo số – levi

+0

Không có khóa chính và tôi không có quyền kiểm soát bảng để bao gồm một cột. – 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... 
    ); 

Ghi chú: SQL-phương ngữ của bạn có thể thay đổi. Note2: "name" là một từ dành riêng trên một số nền tảng. Tốt hơn nên tránh nó.

+0

Nhưng trong câu trả lời của bạn, chúng tôi giả định rằng zname sẽ là duy nhất cho mỗi hàng. Vì bảng không có ràng buộc khóa chính, giả định này sẽ không hợp lệ khi cùng một tên sẽ xuất hiện trong các bản ghi trùng lặp. – Nik

+0

Đó là chính xác. Trong trường hợp đó, bạn sẽ phải sử dụng một row_number. Hầu hết các DMBM có một row_number, nhưng tên khác nhau giữa các nền tảng. (row_num, row_id, tid, ...) Kiểm tra tài liệu. – wildplasser

0

Đây là một biến thể của câu trả lời levenlevi của mà không yêu cầu một khóa chính trên bàn (không thể kiểm tra cú pháp ngay bây giờ 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) 

tôi nghĩ rằng trên iSeries các rid_bit() không được hỗ trợ, nhưng 0.123.lưu cùng một mục đích

1

biến thể của @a_horse_with_no_name answer db2 cho các thư mục mà không sử dụng nhóm theo mệnh đề và trong mệnh đề. Nó thực sự hoạt động

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

Đối với một phiên bản cũ của db2 SQL: Kết hợp các bài viết này đã giúp xác định và loại bỏ các dups từ 2 lô được đăng hai lần.

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); 
Các vấn đề liên quan