Nếu bạn cho rằng một bảng MySQL có thể có các hàng trùng lặp, bạn có thể sử dụng các tùy chọn sau để trả về tất cả các hàng trùng lặp.
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 | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +-------+---------+---------+
Hai hàng đầu tiên trùng lặp, ba hàng cuối cùng cũng vậy. Các hàng trùng lặp có cùng giá trị trên tất cả các cột.
Tùy chọn 1
Một tùy chọn là sử dụng truy vấn sau để trả về các hàng trùng lặp:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Kết quả:
+-------+-------+ | PetId | Count | +-------+-------+ | 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:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Kết quả:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +-------+---------+---------+-------+
Chúng tôi có thể có các bản sao xuất hiện đầu tiên bằng cách sắp xếp nó theo số lượng theo thứ tự giảm dần:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY Count DESC;
Kết quả:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 4 | Bark | Dog | 3 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | +-------+---------+---------+-------+
Tùy chọn 2
Nếu chúng ta chỉ muốn liệt kê các hàng trùng lặp, chúng ta có thể sử dụng HAVING
mệnh đề loại trừ các bản không trùng lặp khỏi đầu ra:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Kết quả:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 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ới PARTITION BY
mệnh đề đánh số đầu ra của tập kết quả.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets;
Kết quả:
+-------+---------+---------+----+ | PetId | PetName | PetType | rn | +-------+---------+---------+----+ | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +-------+---------+---------+----+
PARTITION BY
mệnh đề chia tập kết quả được tạo ra bởi FROM
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
Để chỉ trả về các hàng thặng dư từ các bản sao phù hợp, chúng ta có thể sử dụng truy vấn trên làm biểu thức bảng chung, như sau:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets
)
SELECT * FROM cte WHERE rn <> 1;
Kết quả:
+-------+---------+---------+----+ | PetId | PetName | PetType | rn | +-------+---------+---------+----+ | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +-------+---------+---------+----+