2012-01-22 43 views
9

我有一個模型,由於代碼錯誤,有重複的行。我現在需要刪除數據庫中的任何重複項。刪除Django數據庫中的重複行

每行都應該有一個唯一的photo_id。有沒有簡單的方法來刪除它們?或者我需要做這樣的事情:

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

將來會更好,將該字段定義爲數據庫模式中唯一的字段。然後你消除這個問題從來沒有發生過。實際上,您應該將這些細節添加到所有數據庫模式中。 – Keith

回答

21

最簡單的方法是最簡單的方法!特別是對於那些性能甚至不重要的腳本(除非它確實如此)。既然不是核心代碼,我只想寫出第一個想到的事情,作品

# 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() 

一如既往,備份之前,你做這個東西。

+1

謝謝。你知道一個查詢會告訴我什麼是行嗎?我知道截然不同的人會告訴我沒有軍人的數據庫,但是什麼會讓我看到軍人? – Brenden

+0

'SELECT * FROM table GROUP BY photo_id HAVING COUNT(photo_id)> 1;' –

+0

@brenden,而不是刪除行,您可以將它們追加到列表中?我刪除了我的第二個查詢,因爲我忘記了會匹配重複項和非重複項......關閉一個! –

10

這可能會更快,因爲它避免了MyModel中每行的內部過濾器。由於ID是唯一的,如果模型按遞增順序排序,我們可以跟蹤我們看到的最後一個ID,並且當我們在行上行走時,如果我們看到具有相同ID的模型,它必須是重複的,所以我們可以刪除它。

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

關於性能,這當然是更好的選擇!謝謝,我們需要這個大型數據庫! –

+0

很適合將錶轉換爲具有'unique_together'約束,謝謝! – mlissner

+0

另一個不錯的功能是,它可以讓你通過另一個領域來訂購你想要保留在這些團體的頂部! – hobs

3

這裏是一個快速的解決方案:

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()] 

現在你可以這樣做:

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

,或者如果ids_list是太龐大你的DBMS處理

你可以將其分割爲可以由其處理的塊:

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

這將只刪除其中的一個副本。所以如果有超過2行的話,你必須遞歸地做這件事。所以它可能不會比其他解決方案更快。 – hobs