Xóa các hàng trùng lặp khỏi cơ sở dữ liệu sqlite


91

Tôi có một bảng lớn - 36 triệu hàng - trong SQLite3. Trong bảng rất lớn này, có hai cột:

  • hash - bản văn
  • d - thực tế

Một số hàng bị trùng lặp. Đó là, cả hai hashdcó cùng giá trị. Nếu hai hàm băm giống hệt nhau, thì các giá trị của d. Tuy nhiên, hai chữ giống hệt nhau dkhông có nghĩa là hai chữ cái giống hệt nhau hash.

Tôi muốn xóa các hàng trùng lặp. Tôi không có cột khóa chính.

Cách nhanh nhất để làm điều này là gì?


Vui lòng đặt câu trả lời trong khối Câu trả lời. Sau đó, bạn có thể chấp nhận Câu trả lời của riêng mình. Ngoài ra, hãy xem cách chấp nhận câu trả lời hoạt động như thế nào?
jww

Câu trả lời:


121

Bạn cần một cách để phân biệt các hàng. Dựa trên nhận xét của bạn, bạn có thể sử dụng cột rowid đặc biệt cho việc đó.

Để xóa các bản sao bằng cách giữ mức thấp nhất rowidcho mỗi (hash,d):

delete   from YourTable
where    rowid not in
         (
         select  min(rowid)
         from    YourTable
         group by
                 hash
         ,       d
         )

SQLite không cho phép bạn thêm cột khóa chính, phải không?
Các bản vá

sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
Bản vá lỗi

Hấp dẫn! Phần bạn cần là autoincrementmặc dù, nó có hoạt động nếu bạn bỏ qua primary keyphần đó không?
Andomar

sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error Chỉnh sửa: SQLite có kiểu cột giả "rowid" tự động ở đó, tôi có thể sử dụng cái này không?
Bản vá

1
delete from dist where rowid not in (select max(rowid) from dist group by hash); Xuất hiện để làm thủ thuật! Cảm ơn.
Các bản vá

5

Tôi đoán nhanh nhất sẽ là sử dụng chính cơ sở dữ liệu cho nó: thêm một bảng mới với các cột giống nhau, nhưng với các ràng buộc thích hợp (một chỉ mục duy nhất trên cặp băm / thực?), Lặp qua bảng gốc và cố gắng chèn các bản ghi vào bảng mới, bỏ qua lỗi vi phạm ràng buộc (tức là tiếp tục lặp lại khi các ngoại lệ được nâng lên).

Sau đó xóa bảng cũ và đổi tên bảng mới thành bảng cũ.


Tôi đoán không đơn giản chỉ là thay đổi bảng, NHƯNG một điều thực sự tốt về cách tiếp cận của bạn là bạn có thể chạy lại nó nhiều lần tùy thích mà không cần chạm / phá hủy dữ liệu nguồn cho đến khi bạn hoàn toàn hài lòng với kết quả .
Adrian K

1

Nếu thêm khóa chính không phải là một tùy chọn, thì một cách tiếp cận sẽ là lưu trữ DISTINCT trùng lặp trong bảng tạm thời, xóa tất cả các bản ghi trùng lặp khỏi bảng hiện có, sau đó thêm lại các bản ghi vào bảng gốc từ bảng tạm thời .

Ví dụ (được viết cho SQL Server 2008, nhưng kỹ thuật này giống nhau cho bất kỳ cơ sở dữ liệu nào):

DECLARE @original AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('A', 2)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('B', 1)
INSERT INTO @original VALUES('C', 1)
INSERT INTO @original VALUES('C', 1)

DECLARE @temp AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @temp
SELECT [hash], [d] FROM @original 
GROUP BY [hash], [d]
HAVING COUNT(*) > 1

DELETE O
FROM @original O
JOIN @temp T ON T.[hash] = O.[hash] AND T.[d] = O.[d]

INSERT INTO @original
SELECT [hash], [d] FROM @temp

SELECT * FROM @original

Tôi không chắc sqlite có ROW_NUMBER()hàm loại hay không, nhưng nếu có, bạn cũng có thể thử một số phương pháp được liệt kê ở đây: Xóa bản ghi trùng lặp khỏi bảng SQL mà không có khóa chính


+1, không chắc chắn nếu hỗ trợ sqlite các delete <alias> from <table> <alias>cú pháp mặc dù
Andomar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.