Dưới đây là mười một tùy chọn để trả về các hàng trùng lặp trong SQLite khi các hàng đó có khóa chính hoặc một số cột định danh duy nhất khác (nhưng bạn muốn bỏ qua khóa chính).
Điều này có nghĩa là 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.
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:
SELECT * FROM Dogs;
Kết quả:
DogId FirstName LastName ----- --------- -------- 1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson5 Wag Johnson 6 Wag Johnson 7 Wag JohnsonHai 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 là phương pháp hay trong RDBMS, vì khóa chính giúp thực thi tính toàn vẹn của dữ liệu. Nhưng vì khóa chính ngăn các hàng trùng lặp nên chúng có khả năng cản trở khả năng tìm thấy các hàng trùng lặp của chúng tôi.
Trong bảng của chúng tôi ở trên, 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 ta cần bỏ qua hàng đó nếu chúng ta muốn tìm các bản sao trong các cột khác.
Tùy chọn 1
Chúng tôi có thể chạy một truy vấn với
GROUP BY
để nhóm các cột theo các cột quan trọng của chúng, sau đó sử dụngCOUNT()
hàm trả về số lượng hàng giống nhau:SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName ORDER BY Count DESC;
Kết quả:
FirstName LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2 Ruff Robinson 1 Woof Jones 1Ở đây, chúng tôi đã loại trừ cột khóa chính bằng cách bỏ qua cột đó khỏi truy vấn của chúng tôi. Chúng tôi cũng đã sắp xếp nó theo số lượng theo thứ tự giảm dần để các bản sao xuất hiện đầu tiên.
Kết quả cho chúng ta biết rằng có ba hàng chứa Wag Johnson và hai hàng chứa Bark Smith. Đâ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 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 FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName HAVING COUNT(*) > 1 ORDER BY Count DESC;
Kết quả:
FirstName LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2Tùy chọn 3
Dưới đây là một ví dụ về việc kiểm tra các bản sao trên các cột được nối. Trong trường hợp này, chúng tôi sử dụng
DISTINCT
từ khóa để nhận các giá trị riêng biệt, sau đó sử dụngCOUNT()
hàm để trả về số lượng:SELECT DISTINCT FirstName || ' ' || LastName AS DogName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName || ' ' || LastName ORDER BY Count DESC;
Kết quả:
DogName Count ------------- ----- Wag Johnson 3 Bark Smith 2 Woof Jones 1 Ruff Robinson 1Tùy chọn 4
Theo mặc định, mỗi hàng trong SQLite có một cột đặc biệt, thường được gọi là
rowid
, xác định duy nhất hàng đó trong bảng. Trừ khi nó đã bị xóa rõ ràng khỏi bảng, bạn có thể sử dụng nó làm số nhận dạng duy nhất cho mỗi hàng.Do đó, chúng tôi có thể sử dụng
rowid
trong truy vấn của chúng tôi:SELECT * FROM Dogs WHERE EXISTS ( SELECT 1 FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName AND Dogs.rowid > d2.rowid );
Kết quả:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag JohnsonChúng tôi có thể thay thế
SELECT *
vớiDELETE
để thực hiện thao tác khử trùng lặp trên bảng.Lưu ý rằng chúng tôi có thể đã sử dụng
DogId
cột (khóa chính của chúng tôi) thay vìrowid
nếu chúng tôi muốn. Điều đó nói rằng,rowid
có thể hữu ích nếu bạn không thể sử dụng cột khóa chính vì lý do nào đó hoặc nếu bảng không có khóa chính.Tùy chọn 5
Đây là một truy vấn khác sử dụng
rowid
:SELECT * FROM Dogs WHERE rowid > ( SELECT MIN(rowid) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Kết quả:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag JohnsonNhư với ví dụ trước, chúng ta có thể thay thế
SELECT *
vớiDELETE
để xóa các hàng trùng lặp.Tùy chọn 6
Hai
rowid
các tùy chọn ở trên là rất tốt nếu bạn phải hoàn toàn bỏ qua khóa chính trong truy vấn của mình (hoặc nếu bạn hoàn toàn không có cột khóa chính). Tuy nhiên, như đã đề cập, vẫn có tùy chọn thay thếrowid
với cột khóa chính - trong trường hợp của chúng tôi làDogId
cột:SELECT * FROM Dogs WHERE EXISTS ( SELECT 1 FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName AND Dogs.DogId > d2.DogId );
Kết quả:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag JohnsonTùy chọn 7
Và đây là truy vấn khác với
rowid
được thay thế bằngDogId
cột:SELECT * FROM Dogs WHERE DogId > ( SELECT MIN(DogId) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Kết quả:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag JohnsonTùy chọn 8
Một cách khác để làm điều đó là sử dụng
ROW_NUMBER()
chức năng cửa sổ:SELECT *, ROW_NUMBER() OVER ( PARTITION BY FirstName, LastName ORDER BY FirstName, LastName ) AS Row_Number FROM Dogs;
Kết quả:
DogId FirstName LastName Row_Number ----- ---------------- ---------- 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 1Sử dụng
PARTITION
mệnh đề dẫn đến một cột mới được thêm vào, với số hàng tăng lên mỗi khi có một bản sao, nhưng đặt lại lần nữa khi có một hàng duy nhất.Trong trường hợp này, chúng tôi không nhóm các kết quả, có nghĩa là chúng tôi 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 9
Chúng ta cũng 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 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Điều đó 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.
Tùy chọn 10
Đây là một cách khác để có được đầu ra giống như ví dụ trước:
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 JohnsonTùy chọn 11
Dưới đây là một tùy chọn khác để chọn các bản sao từ bảng của chúng tôi:
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