2011-11-18 134 views
75

我有一個巨大的表 - 3600萬行 - 在SQLite3中。從sqlite數據庫中刪除重複的行

在這個非常大的表,有兩列

  • 哈希 - 文本
  • d - 真正

然而,某些行是重複的。也就是說,哈希和d都具有相同的值。

另外,如果兩個散列是相同的,所以都是d的值,但兩個相同的DS並不意味着兩個相同的哈希

不管怎樣,我想刪除重複的行。我沒有主鍵列。 這樣做的最快方法是什麼?


編輯:delete from dist where rowid not in (select max(rowid) from dist group by hash);

出現這樣的伎倆。

+2

+1你的'EDIT'已經節省了我很多時間... :) – Ankur

+0

同意。 @Patches編輯直接爲我工作 –

+1

得愛自我意識的評論:「我沒有主鍵列,因爲我是一個白癡」:) – dwanderson

回答

94

您需要一種方法來區分行。根據你的評論,你可以使用特殊的rowid column

要通過保持刪除重複的最低rowid(hash,d)

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

SQLite不允許您添加主鍵列,是嗎? – Patches

+0

'sqlite> alter table dist add id整數主鍵autoincrement; 錯誤:無法添加PRIMARY KEY列' – Patches

+0

有趣!你需要的部分是'autoincrement',但是如果你省略'primary key'部分,它會起作用嗎? – Andomar

1

如果添加主鍵不是選項,那麼一種方法是將重複的DISTINCT存儲在臨時表中,從現有表中刪除所有重複記錄,然後將記錄添加回原始表中從臨時表中。

例如(寫爲SQL Server 2008,但該技術爲任何數據庫中的相同):

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 

我不知道如果sqlite的有ROW_NUMBER()類型的功能,但如果這樣做你可以還請嘗試下面列出的一些方法:Delete duplicate records from a SQL table without a primary key

+0

+1,不知道如果sqlite支持'刪除

'語法雖然 – Andomar

4

我想最快的將是使用非常數據庫是:添加一個新表具有相同的列,但適當的約束(哈希/實數對上的唯一索引?),迭代原始表並嘗試在新表中插入記錄,忽略約束違規錯誤(即在引發異常時繼續迭代)。

然後刪除舊錶並將新名稱重命名爲舊名稱。

+0

不像簡單地改變表格一樣優雅,我想,但是你的方法的一個真正好處是,你可以重新運行它多次,只要你喜歡,而不接觸/銷燬源數據,直到你絕對滿意爲止結果。 –