Dưới đây là bốn phương pháp bạn có thể sử dụng để tìm các hàng trùng lặp trong SQL Server.
"Các hàng trùng lặp", ý tôi là hai hoặc nhiều hàng chia sẻ chính xác các giá trị giống nhau trên tất cả các cột.
Dữ liệu Mẫu
Giả sử chúng ta có một bảng với dữ liệu sau:
SELECT * FROM Pets;
Kết quả:
+ --------- + ----------- + ----------- + | PetId | PetName | PetType || --------- + ----------- + ----------- || 1 | Wag | Con chó || 1 | Wag | Con chó || 2 | Cào | Con mèo || 3 | Tweet | Con chim || 4 | Vỏ cây | Con chó || 4 | Vỏ cây | Con chó || 4 | Vỏ cây | Con chó | + --------- + ----------- + ----------- +
Chúng ta có thể thấy rằng hai hàng đầu tiên là trùng lặp, ba hàng cuối cùng cũng vậy.
Tùy chọn 1
Chúng tôi có thể sử dụng truy vấn sau để trả về thông tin về các hàng trùng lặp:
CHỌN DISTINCT PetId, COUNT (*) AS "Đếm" TỪ PetsGROUP BY PetIdORDER BY PetId;
Kết quả:
+ --------- + --------- + | PetId | Tính || --------- + --------- || 1 | 2 || 2 | 1 || 3 | 1 || 4 | 3 | + --------- + --------- +
Chúng tôi có thể mở rộng SELECT
danh sách để bao gồm nhiều cột hơn nếu cần:
CHỌN PetId, PetName, PetType, COUNT (*) AS "Count" TỪ PetsGROUP THEO PetId, PetName, PetTypeORDER BY PetId;
Kết quả:
+ --------- + ----------- + ----------- + --------- + | PetId | PetName | PetType | Tính || --------- + ----------- + ----------- + --------- || 1 | Wag | Con chó | 2 || 2 | Cào | Con mèo | 1 || 3 | Tweet | Chim | 1 || 4 | Vỏ cây | Con chó | 3 | + --------- + ----------- + ----------- + --------- +Nếu bảng có một số nhận dạng duy nhất, chúng ta có thể chỉ cần xóa cột đó khỏi truy vấn. Ví dụ:nếu chúng ta giả định rằng
PetId
thực ra là cột khóa chính chứa một ID duy nhất, chúng tôi có thể chạy truy vấn sau để trả về tất cả các hàng trùng lặp, không tính cột khóa chính:CHỌN PetName, PetType, COUNT (*) AS "Count" FROM PetsGROUP BY PetName, PetTypeORDER BY PetName;
Kết quả:
+ ----------- + ----------- + --------- + | PetName | PetType | Tính || ----------- + ----------- + --------- || Vỏ cây | Con chó | 3 || Cào | Con mèo | 1 || Tweet | Chim | 1 || Wag | Con chó | 2 | + ----------- + ----------- + --------- +Tùy chọn 2
Nếu chúng tôi chỉ muốn trả về các hàng trùng lặp thực tế, chúng tôi có thể thêm
HAVING
mệnh đề:CHỌN PetId, PetName, PetType, COUNT (*) AS "Count" TỪ PetsGROUP BY PetId, PetName, PetTypeHAVING COUNT (*)> 1ORDER BY PetId;
Kết quả:
+ --------- + ----------- + ----------- + --------- + | PetId | PetName | PetType | Tính || --------- + ----------- + ----------- + --------- || 1 | Wag | Con chó | 2 || 4 | Vỏ cây | Con chó | 3 | + --------- + ----------- + ----------- + --------- +Tùy chọn 3
Một cách khác để làm điều đó là sử dụng
ROW_NUMBER ()
chức năng vớiPARTITION BY
mệnh đề đánh số đầu ra của tập kết quả.SELECT *, ROW_NUMBER () OVER (PHẦN THỨ BỞI PetId, PetName, PetType ORDER BY PetId, PetName, PetType) AS Row_NumberFROM Pets;
Kết quả:
+ --------- + ----------- + ----------- + ------------ - + | PetId | PetName | PetType | Row_Number || --------- + ----------- + ----------- + ------------- - || 1 | Wag | Con chó | 1 || 1 | Wag | Con chó | 2 || 2 | Cào | Con mèo | 1 || 3 | Tweet | Chim | 1 || 4 | Vỏ cây | Con chó | 1 || 4 | Vỏ cây | Con chó | 2 || 4 | Vỏ cây | Con chó | 3 | + --------- + ----------- + ----------- + ------------- - +
PARTITION BY
mệnh đề chia tập kết quả được tạo ra bởiFROM
mệnh đề thành các phân vùng mà hàm được áp dụng. Khi chúng ta chỉ định phân vùng cho tập kết quả, mỗi phân vùng sẽ làm cho việc đánh số bắt đầu lại (tức là việc đánh số sẽ bắt đầu từ 1 cho hàng đầu tiên trong mỗi phân vùng).Tùy chọn 4
Nếu chúng tôi chỉ muốn các hàng thặng dư từ các bản sao phù hợp được trả lại, chúng tôi có thể sử dụng truy vấn trên làm biểu thức bảng chung, như sau:
VỚI CTE AS (SELECT *, ROW_NUMBER () OVER (PARTITION BY PetId, PetName, PetType ORDER BY PetId, PetName, PetType) AS Row_Number FROM Pets) CHỌN * TỪ CTE WHERE Row_Number <> 1;
Kết quả:
+ --------- + ----------- + ----------- + ------------ - + | PetId | PetName | PetType | Row_Number || --------- + ----------- + ----------- + ------------- - || 1 | Wag | Con chó | 2 || 4 | Vỏ cây | Con chó | 2 || 4 | Vỏ cây | Con chó | 3 | + --------- + ----------- + ----------- + ------------- - +Một trong những lợi ích của việc này là chúng ta có thể xóa các hàng trùng lặp chỉ bằng cách chuyển đổi
SELECT *
thànhDELETE
(ở dòng cuối cùng).Do đó, chúng tôi có thể sử dụng mã trên để xem những hàng nào sẽ bị xóa và sau đó khi chúng tôi hài lòng rằng chúng tôi sẽ xóa các hàng chính xác, chúng tôi có thể chuyển nó thành
DELETE
tuyên bố để thực sự xóa chúng.Như thế này:
VỚI CTE AS (SELECT *, ROW_NUMBER () OVER (PARTITION BY PetId, PetName, PetType ORDER BY PetId, PetName, PetType) AS Row_Number FROM Pets) XÓA khỏi CTE WHERE Row_Number <> 1;