2012-01-22 60 views
9

Tôi có một mô hình do lỗi mã, có các hàng trùng lặp. Bây giờ tôi cần xóa bất kỳ bản sao nào khỏi cơ sở dữ liệu.Xóa hàng trùng lặp trong Django DB

Mọi hàng phải có photo_id duy nhất. Có cách nào đơn giản để xóa chúng? Hoặc tôi có cần phải làm điều gì đó như thế này:

rows = MyModel.objects.all() 
for row in rows: 
    try: 
     MyModel.objects.get(photo_id=row.photo_id) 
    except: 
     row.delete() 
+0

Sẽ tốt hơn, trong tương lai, để xác định trường đó là duy nhất trong giản đồ cơ sở dữ liệu của bạn. Sau đó, bạn loại bỏ vấn đề này từ bao giờ xảy ra. Trong thực tế, bạn nên thêm các chi tiết đó vào tất cả lược đồ cơ sở dữ liệu của bạn. – Keith

Trả lời

21

Cách đơn giản nhất là cách đơn giản nhất! Đặc biệt là cho một kịch bản tắt mà hiệu suất thậm chí không quan trọng (trừ khi nó không). Vì nó không phải là mã cốt lõi, tôi chỉ viết điều đầu tiên xuất hiện trong đầu và hoạt động.

# assuming which duplicate is removed doesn't matter... 
for row in MyModel.objects.all(): 
    if MyModel.objects.filter(photo_id=row.photo_id).count() > 1: 
     row.delete() 

Như thường lệ, hãy sao lưu trước khi bạn thực hiện công cụ này.

+1

Cảm ơn. Bạn có biết một truy vấn chỉ hiển thị cho tôi những hàng nào là dups không? Tôi biết rõ ràng sẽ chỉ cho tôi db mà không có dups, nhưng những gì sẽ chỉ cho tôi chỉ dups? – Brenden

+0

'SELECT * TỪ bảng GROUP BY photo_id ĐANG COUNT (photo_id)> 1;' –

+0

@brenden, thay vì xóa các hàng, bạn có thể thêm chúng vào danh sách? Tôi đã xóa truy vấn thứ hai của mình vì tôi quên rằng sẽ khớp với cả hai bản sao và không trùng lặp ... đóng một! –

10

Điều này có thể nhanh hơn vì nó tránh bộ lọc bên trong cho mỗi hàng trong MyModel.

Vì các id là duy nhất, nếu chúng được sắp xếp theo thứ tự tăng dần, chúng tôi có thể theo dõi id cuối cùng mà chúng ta đã thấy và khi chúng ta đi qua các hàng nếu chúng ta thấy một mô hình có cùng id, là một bản sao, vì vậy chúng tôi có thể xóa nó.

lastSeenId = float('-Inf') 
rows = MyModel.objects.all().order_by('photo_id') 

for row in rows: 
    if row.photo_id == lastSeenId: 
    row.delete() # We've seen this id in a previous row 
    else: # New id found, save it and check future rows for duplicates. 
    lastSeenId = row.photo_id 
+2

Về hiệu suất, đó chắc chắn là lựa chọn tốt hơn! Cảm ơn, chúng tôi cần điều này cho một cơ sở dữ liệu lớn! –

+0

Hoạt động tốt để chuyển đổi bảng cũng có ràng buộc 'unique_together', cảm ơn! – mlissner

+0

Một tính năng thú vị khác là nó cho phép bạn đặt hàng bởi một trường khác để giữ những thứ bạn muốn giữ ở đầu các nhóm lừa đảo! – hobs

3

Dưới đây là một giải pháp nhanh chóng:

from django.db import connection 

query = "SELECT id FROM table_name GROUP BY unique_column HAVING COUNT(unique_column)>1" 
cursor = connection.cursor() 
cursor.execute(query) 
ids_list = [item[0] for item in cursor.fetchall()] 

bây giờ bạn có thể làm:

Some_Model.objects.filter(id__in=ids_list).delete() 

hoặc nếu ids_list đã quá lớn để được xử lý bởi DBMS của bạn

bạn có thể phân đoạn thành các phần có thể được xử lý bởi:

seg_length = 100 
ids_lists = [ids_list[x:x+seg_length] for x in range(0,len(ids_list),seg_length)] 
for ids_list in ids_lists: 
    SomeModel.objects.filter(id__in=ids_list).delete() 
+0

Thao tác này sẽ chỉ xóa 1 trong số các mục trùng lặp.Vì vậy, bạn phải làm điều này đệ quy nếu có nhiều hơn 2 của bất kỳ hàng nào. Vì vậy, nó có thể không nhanh hơn các giải pháp khác. – hobs

Các vấn đề liên quan