Menghapus baris duplikat dari database sqlite

92

Saya memiliki tabel besar - 36 juta baris - di SQLite3. Dalam tabel yang sangat besar ini, ada dua kolom:

  • hash - teks
  • d - nyata

Beberapa baris merupakan duplikat. Artinya, keduanya hashdan dmemiliki nilai yang sama. Jika dua hash identik, maka nilai dari d. Namun demikian, dua hal yang identik dtidak berarti dua hal yang identik hash.

Saya ingin menghapus baris duplikat. Saya tidak memiliki kolom kunci utama.

Apa cara tercepat untuk melakukan ini?

Tambalan
sumber
Tolong tempatkan jawaban di blok Jawaban. Nanti, Anda dapat menerima Jawaban Anda sendiri. Lihat juga Bagaimana cara kerja menerima jawaban?
jww

Jawaban:

122

Anda membutuhkan cara untuk membedakan baris. Berdasarkan komentar Anda, Anda dapat menggunakan kolom rowid khusus untuk itu.

Untuk menghapus duplikat dengan mempertahankan nilai terendah rowidper (hash,d):

delete   from YourTable
where    rowid not in
         (
         select  min(rowid)
         from    YourTable
         group by
                 hash
         ,       d
         )
Andomar
sumber
SQLite tidak mengizinkan Anda menambahkan kolom kunci utama, bukan?
Menambal
sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
Menambal
Menarik! Bagian yang Anda butuhkan adalah autoincrement, apakah berfungsi jika Anda menghilangkan primary keybagian tersebut?
Andomar
sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error Sunting: SQLite memang memiliki jenis kolom semu "rowid" yang secara otomatis ada di sana, dapatkah saya menggunakan ini?
Menambal
1
delete from dist where rowid not in (select max(rowid) from dist group by hash); Tampaknya berhasil! Terima kasih.
Menambal
5

Saya kira yang tercepat adalah menggunakan database untuk itu: tambahkan tabel baru dengan kolom yang sama, tetapi dengan batasan yang tepat (indeks unik pada pasangan hash / nyata?), Ulangi melalui tabel asli dan coba masukkan catatan di tabel baru, mengabaikan kesalahan pelanggaran batasan (yaitu melanjutkan iterasi ketika pengecualian dimunculkan).

Kemudian hapus tabel lama dan ganti nama yang baru ke yang lama.

MaDa
sumber
Tidak seanggun hanya dengan mengubah tabel, saya rasa, TETAPI satu hal yang sangat baik tentang pendekatan Anda adalah Anda dapat menjalankannya kembali sebanyak yang Anda suka tanpa menyentuh / menghancurkan data sumber sampai Anda benar-benar puas dengan hasilnya. .
Adrian K
1

Jika menambahkan kunci utama bukan merupakan pilihan, maka salah satu pendekatannya adalah menyimpan duplikat berbeda dalam tabel temp, Hapus semua rekaman duplikat dari tabel yang sudah ada, lalu tambahkan rekaman kembali ke tabel asli dari tabel temp .

Misalnya (ditulis untuk SQL Server 2008, tetapi tekniknya sama untuk database apa pun):

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

Saya tidak yakin apakah sqlite memiliki ROW_NUMBER()fungsi tipe, tetapi jika ya, Anda juga dapat mencoba beberapa pendekatan yang tercantum di sini: Hapus catatan duplikat dari tabel SQL tanpa kunci utama

rsbarro.dll
sumber
+1, tidak yakin apakah sqlite mendukung delete <alias> from <table> <alias>sintaksis
Andomar