JuniorLập trìnhSQL
Viết query tìm và xóa các dòng trùng lặp
Thử trả lời trước
Đáp án mẫu
Trước tiên tìm các dòng trùng bằng cách group theo những cột định nghĩa "cùng một dòng":
SELECT email, COUNT(*) AS copies
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
Để xóa, giữ lại một dòng trong mỗi nhóm và xóa phần còn lại. ROW_NUMBER() đánh số các dòng trong từng nhóm trùng, mọi dòng sau dòng đầu đều là dòng thừa:
DELETE FROM users
WHERE id IN (
SELECT id FROM (
SELECT id,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn
FROM users
) t
WHERE rn > 1
);
ORDER BY id giữ dòng cũ nhất, đổi chiều sort nếu muốn giữ dòng mới nhất. Derived table bọc ngoài cần cho MySQL, vì MySQL không cho xóa từ một bảng mà cũng đọc trong subquery thường.
Trước khi xóa, hãy chạy SELECT bên trong và kiểm tra số lượng, và làm trong transaction hoặc trên bản backup. Sau đó chặn vấn đề từ gốc:
ALTER TABLE users ADD CONSTRAINT uq_users_email UNIQUE (email);
Sửa nguyên nhân bằng unique constraint, nếu không dữ liệu trùng sẽ quay lại.
Ý chính
- GROUP BY với HAVING COUNT(*) > 1 tìm các key trùng
- ROW_NUMBER đánh dấu bản sao nào cần xóa
- Xem trước và dùng transaction trước khi xóa
- Unique constraint ngăn dữ liệu trùng mới
Câu hỏi nối tiếp thường gặp
- Bạn khử trùng thế nào khi email chỉ khác nhau về chữ hoa thường?
Lỗi thường gặp
- Xóa dữ liệu trùng mà không thêm unique constraint
- Chạy DELETE mà không xem trước những dòng sẽ bị xóa