Cách đơn giản nhất là với CTE (biểu thức bảng chung). Tôi sử dụng phương pháp này khi tôi có dữ liệu thô để nhập; điều đầu tiên tôi làm để làm sạch nó là để đảm bảo không có bản sao --- rằng tôi có một số loại xử lý duy nhất cho mỗi hàng.
Tóm tắt:
WITH numbered AS (
SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num FROM [table-name] WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;
Phần "dupe-column-list" là nơi bạn liệt kê tất cả các cột có liên quan mà bạn muốn các giá trị là duy nhất. ORDER BY là nơi bạn quyết định, trong một tập hợp các bản sao, hàng nào "thắng" và hàng nào bị xóa. ("WHERE 1 =1" chỉ là một thói quen cá nhân.)
Lý do nó hoạt động là vì Sql Server giữ một tham chiếu nội bộ, duy nhất cho mỗi hàng nguồn được chọn trong CTE. Vì vậy, khi DELETE được thực thi, nó sẽ biết chính xác hàng cần xóa, bất kể bạn đặt gì trong danh sách chọn của CTE. (Nếu bạn lo lắng, bạn có thể thay đổi "XÓA" thành "CHỌN *", nhưng vì bạn có các hàng trùng lặp, điều đó sẽ không hữu ích; nếu bạn có thể xác định duy nhất từng hàng, bạn sẽ không đọc được .)
Ví dụ:
CREATE TABLE ##_dupes (col1 int, col2 int, col3 varchar(50));
INSERT INTO ##_dupes
VALUES (1, 1, 'one,one')
, (2, 2, 'two,two')
, (3, 3, 'three,three')
, (1, 1, 'one,one')
, (1, 2, 'one,two')
, (3, 3, 'three,three')
, (1, 1, 'one,one')
, (1, 2, '1,2');
Trong số 8 hàng, bạn có 5 hàng liên quan đến các vấn đề trùng lặp; 3 hàng cần được xóa. Bạn có thể thấy các vấn đề với điều này:
SELECT col1
, col2
, col3
, COUNT(1) AS _total
FROM ##_dupes
WHERE 1=1
GROUP BY col1, col2, col3
HAVING COUNT(1) > 1
ORDER BY _total DESC;
Bây giờ, hãy chạy truy vấn sau để loại bỏ các bản sao, để lại 1 hàng từ mỗi tập hợp các bản sao.
WITH numbered AS (
SELECT ROW_NUMBER() OVER(PARTITION BY col1, col2, col3 ORDER BY col1, col2, col3) AS _dupe_num FROM ##_dupes WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;
Bây giờ bạn còn lại 5 hàng, không có hàng nào bị trùng lặp.