Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

3 cách để xóa các dòng trùng lặp trong SQL Server khi bỏ qua khóa chính

Các ví dụ sau sử dụng T-SQL để xóa các hàng trùng lặp trong SQL Server trong khi bỏ qua khóa chính hoặc cột định danh duy nhất.

Cụ thể hơn, các ví dụ xóa các hàng trùng lặp nhưng giữ lại một hàng. Vì vậy, với hai hàng giống hệt nhau, một hàng bị xóa và hàng còn lại vẫn còn. Điều này thường được gọi là "khử trùng lặp" bảng, "trùng lặp" bảng, v.v.

Dữ liệu mẫu

Giả sử chúng ta có một bảng với dữ liệu sau:

SELECT * FROM Dogs;

Kết quả:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Chúng ta có thể thấy rằng hai hàng đầu tiên là trùng lặp và ba hàng cuối cùng cũng vậy.

Tùy chọn 1

Đầu tiên, hãy chạy đoạn mã sau để kiểm tra xem hàng nào sẽ được loại bỏ:

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Kết quả:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 2       | Bark        | Smith      | 2            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
+---------+-------------+------------+--------------+

Chúng tôi đã sử dụng ROW_NUMBER() chức năng với PARTITION BY mệnh đề để tạo số hàng của riêng chúng ta tăng lên khi tìm thấy bất kỳ bản sao nào và đặt lại khi tìm thấy bản không trùng lặp. Một số lớn hơn 1 cho biết đó là một bản sao và do đó chúng tôi chỉ trả về các hàng có số lớn hơn 1.

Chúng ta có thể thấy rằng ba hàng sẽ bị xóa khi chúng ta loại bỏ bảng này.

Bây giờ chúng ta hãy phân tích bảng:

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
DELETE FROM cte WHERE Row_Number <> 1;

Kết quả:

(3 rows affected)

Như mong đợi, ba hàng đã bị xóa.

Truy vấn này gần giống với truy vấn trước đó. Tất cả những gì chúng tôi đã làm là thay đổi SELECT * trên dòng cuối cùng đến DELETE .

Bây giờ, hãy chọn tất cả các hàng từ bảng để xác minh rằng các hàng chính xác đã bị xóa:

SELECT * FROM Dogs;

Kết quả:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Chúng ta có thể thấy rằng mỗi con chó hiện chỉ xuất hiện một lần trong bảng.

Tùy chọn 2

Giả sử rằng bảng đã được khôi phục sau ví dụ trước, đây là một cách khác để kiểm tra các bản sao:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Kết quả:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Trong trường hợp này, chúng tôi đã sử dụng EXCEPT toán tử cùng với MIN() hàm số. Chúng tôi có thể thay thế MIN() với MAX() tùy thuộc vào hàng mà chúng tôi muốn xóa.

Để xóa các hàng, chúng ta chỉ cần thay thế SELECT * với DELETE :

DELETE FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Kết quả:

(3 rows affected)

Và kiểm tra xem những gì còn lại:

SELECT * FROM Dogs;

Kết quả:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Tùy chọn 3

Một cách khác để làm điều đó là tự tham gia vào bảng và kiểm tra các bản sao theo cách đó.

Giả sử rằng bảng đã được khôi phục sau ví dụ trước, đây là tùy chọn thứ ba của chúng tôi để chọn các bản sao:

SELECT * 
FROM Dogs d1, Dogs d2 
WHERE d1.FirstName = d2.FirstName 
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId 
AND d1.DogId = (
    SELECT MAX(DogId) 
    FROM Dogs d3 
    WHERE d3.FirstName = d1.FirstName 
    AND d3.LastName = d1.LastName
);

Kết quả:

+---------+-------------+------------+---------+-------------+------------+
| DogId   | FirstName   | LastName   | DogId   | FirstName   | LastName   |
|---------+-------------+------------+---------+-------------+------------|
| 2       | Bark        | Smith      | 1       | Bark        | Smith      |
| 7       | Wag         | Johnson    | 5       | Wag         | Johnson    |
| 7       | Wag         | Johnson    | 6       | Wag         | Johnson    |
+---------+-------------+------------+---------+-------------+------------+

Kết quả này không hoàn toàn rõ ràng như kết quả trong ví dụ trước, nhưng chúng ta vẫn có thể thấy hàng nào trùng lặp.

Bây giờ chúng ta có thể sửa đổi truy vấn đó để xóa các hàng trùng lặp:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MAX(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);

Kết quả:

(3 rows affected)

Một lần nữa, ba hàng đã bị xóa.

Hãy kiểm tra lại bảng:

SELECT * FROM Dogs;

Kết quả:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Bạn có thể nhận thấy rằng lần này các hàng khác đã bị xóa. Nói cách khác, bây giờ chúng ta có DogId s 2, 3, 4 và 7 trong khi trong các ví dụ trước, chúng ta chỉ còn lại 1, 3, 4 và 5.

Chúng ta có thể dễ dàng thay đổi ví dụ này để xóa các hàng giống như các ví dụ trước. Để làm điều này, chúng ta có thể sử dụng MIN() thay vì MAX() chức năng:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bảo trì theo lịch trình của Cơ sở dữ liệu IS 24/7 trong MS SQL Server

  2. Kết nối với máy chủ SQL với xác thực Windows từ máy Linux thông qua JDBC

  3. Gọi thủ tục được lưu trữ với tham số có giá trị bảng từ java

  4. Nhận AVG bỏ qua giá trị Null hoặc Zero

  5. Cách tạo dữ liệu kiểm tra trong SQL Server