SQLiteデータベースから重複する行を削除する


91

SQLite3には、3600万行の巨大なテーブルがあります。この非常に大きなテーブルには、2つの列があります。

  • hash -テキスト
  • d -本物

一部の行が重複しています。つまり、hashdは同じ値を持っています。2つのハッシュが同じ場合、の値も同じですd。ただし、2つの同一dのが2つの同一であることを意味するわけではありませんhashのを。

重複する行を削除したい。主キー列はありません。

これを行う最速の方法は何ですか?


回答は回答ブロックに入れてください。後で、自分の回答を受け入れることができます。また、回答の受け入れ
jww

回答:


120

行を区別する方法が必要です。コメントに基づいて、そのために特別なROWID列を使用できます。

最小値を維持して重複を削除するにrowid(hash,d)

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

SQLiteでは、主キー列を追加できませんか?
パッチは

sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
パッチは

面白い!必要な部分autoincrementはそれでもですが、そのprimary key部分を省略しても機能しますか?
Andomar

sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error 編集:SQLiteには「rowid」疑似列タイプのものがありますが、自動的にそこにあります。これを使用できますか?
パッチ

1
delete from dist where rowid not in (select max(rowid) from dist group by hash); トリックを行うように見えます!ありがとう。
パッチ

5

データベースをそのまま使用するのが最も速いと思います:同じ列を持つ新しいテーブルを追加しますが、適切な制約(ハッシュ/実際のペアの一意のインデックス)を使用して、元のテーブルを反復処理し、レコードを挿入してみます制約違反エラーを無視して新しいテーブルを作成します(つまり、例外が発生したときに繰り返し処理を続行します)。

次に、古いテーブルを削除して、新しい名前を古いテーブルに変更します。


単にテーブルを変更するほどエレガントではありませんが、あなたのアプローチの本当に良い点の1つは、結果に完全に満足するまで、ソースデータを変更したり破棄したりせずに、何度でも再実行できることです。 。
エイドリアンK

1

主キーの追加がオプションではない場合、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()タイプ関数があるかどうかはわかりませんが、ある場合は、ここにリストされているアプローチのいくつかを試すこともできます:主キーなしでSQLテーブルから重複レコードを削除する


+1、delete <alias> from <table> <alias>ただし、sqliteが構文をサポートしているかどうかは不明
Andomar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.