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

7 cách tìm hàng trùng lặp khi bỏ qua khóa chính trong MySQL

Dưới đây là bảy cách để trả về các hàng trùng lặp trong MySQL khi các hàng đó có khóa chính hoặc cột định danh duy nhất khác.

Dữ liệu Mẫu

Chúng tôi sẽ sử dụng dữ liệu sau cho các ví dụ của chúng tôi:

DROP TABLE IF EXISTS Dogs;
CREATE TABLE Dogs (
    DogId int PRIMARY KEY NOT NULL,
    FirstName varchar(50),
    LastName varchar(50)
    );

INSERT INTO Dogs VALUES
    (1, 'Bark', 'Smith'),
    (2, 'Bark', 'Smith'),
    (3, 'Woof', 'Jones'),
    (4, 'Ruff', 'Robinson'),
    (5, 'Wag', 'Johnson'),
    (6, 'Wag', 'Johnson'),
    (7, 'Wag', 'Johnson');
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  |
+-------+-----------+----------+

Các hàng trùng lặp chia sẻ chính xác các giá trị giống nhau trên tất cả các cột ngoại trừ khóa chính / cột ID duy nhất của chúng.

Hai hàng đầu tiên trùng lặp (ngoại trừ DogId , là khóa chính của bảng và chứa một giá trị duy nhất trên tất cả các hàng). Ba hàng cuối cùng cũng trùng lặp (ngoại trừ DogId cột).

Cột khóa chính đảm bảo rằng không có hàng trùng lặp, đây thường là một điều tốt trong RDBMS. Tuy nhiên, theo định nghĩa, điều này có nghĩa là không có bản sao. Trong trường hợp của chúng tôi, cột khóa chính là một số tăng dần và giá trị của nó không có ý nghĩa và không quan trọng. Do đó, chúng tôi cần phải bỏ qua hàng đó nếu chúng tôi muốn tìm các bản sao trong các cột có ý nghĩa.

Tùy chọn 1

Tùy chọn đầu tiên của chúng tôi là sử dụng GROUP BY mệnh đề để nhóm các cột theo các cột quan trọng của chúng, sau đó sử dụng COUNT() hàm trả về số lượng hàng giống nhau:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;

Kết quả:

+-----------+----------+-------+
| FirstName | LastName | Count |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Chúng tôi có thể bỏ qua cột khóa chính bằng cách bỏ qua cột đó khỏi truy vấn của mình.

Kết quả cho chúng ta biết rằng có hai hàng chứa Bark Smith và ba hàng chứa Wag Johnson. Đây là các bản sao (hoặc bản sao ba bản trong trường hợp của Wag Johnson). Hai hàng còn lại không có bất kỳ bản sao nào.

Tùy chọn 2

Chúng tôi có thể loại trừ các trường hợp không trùng lặp khỏi đầu ra bằng HAVING mệnh đề:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;

Kết quả:

+-----------+----------+-------+
| FirstName | LastName | Count |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Tùy chọn 3

Chúng tôi cũng có thể kiểm tra các bản sao trên các cột được nối. Ví dụ:chúng ta có thể sử dụng CONCAT() để nối hai cột của chúng ta, sử dụng DISTINCT từ khóa để nhận các giá trị riêng biệt, sau đó sử dụng COUNT() hàm để trả về số lượng:

SELECT
    DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);

Kết quả:

+---------------+-------+
| DogName       | Count |
+---------------+-------+
| Bark Smith    |     2 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Tùy chọn 4

Ngoài ra, chúng tôi có thể sử dụng ROW_NUMBER() chức năng với PARTITION BY mệnh đề:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS rn
FROM Dogs;

Kết quả:

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

Điều này tạo ra một cột mới với số hàng tăng lên mỗi khi có một bản sao, nhưng sẽ đặt lại khi có một hàng duy nhất

Kỹ thuật này mang lại lợi ích có thể có mà chúng ta không cần phải nhóm các kết quả lại. Điều này có nghĩa là chúng ta có thể thấy từng hàng trùng lặp, bao gồm cả cột định danh duy nhất của nó.

Tùy chọn 5

Chúng ta có thể sử dụng ví dụ trước làm biểu thức bảng chung trong một truy vấn lớn hơn:

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

Kết quả:

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

Kỹ thuật này loại trừ các bản không trùng lặp khỏi đầu ra và nó loại trừ một hàng của mỗi bản sao khỏi đầu ra.

Truy vấn này có thể được sử dụng như một tiền thân của một hoạt động gỡ bỏ lừa đảo. Nó có thể cho chúng tôi biết những gì sẽ bị xóa nếu chúng tôi quyết định xóa các bản sao. Để xóa dữ liệu bảng, tất cả những gì chúng ta cần làm là thay thế SELECT * cuối cùng với DELETE .

Tùy chọn 6

Dưới đây là một cách ngắn gọn hơn để có được kết quả giống như ví dụ trước:

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

Kết quả:

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

Kỹ thuật này không yêu cầu chúng tôi tạo một số hàng riêng biệt với ROW_NUMBER() như trong ví dụ trước.

Chúng tôi cũng có thể thay thế SELECT * với DELETE để xóa các bản sao.

Tùy chọn 7

Và cuối cùng, đây là một tùy chọn khác để trả lại 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  |
+-------+-----------+----------+-------+-----------+----------+

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Truy vấn MySQL

  2. Nhiều thứ hạng trong một bảng

  3. Tính toán decile trong MySQL dựa trên tổng số

  4. Làm cách nào để đổi tên tệp đã tải lên trước khi lưu vào thư mục?

  5. Cách theo dõi các chỉ số HAProxy với ClusterControl