Yinelenen satırları sqlite veritabanından silme


92

SQLite3'te 36 milyon satırlık büyük bir tablom var. Bu çok büyük tabloda iki sütun var:

  • hash - Metin
  • d - gerçek

Satırlardan bazıları yineleniyor. Yani, hem hashve daynı değerlere sahip. İki karma özdeşse, değerleri de öyledir d. Bununla birlikte, iki özdeş d" iki özdeş " anlamına gelmez hash.

Yinelenen satırları silmek istiyorum. Birincil anahtar sütunum yok.

Bunu yapmanın en hızlı yolu nedir?


Lütfen cevapları Cevap bloklarına yerleştirin. Daha sonra kendi Cevabınızı kabul edebilirsiniz. Ayrıca bkz. Bir cevabı kabul etmek nasıl çalışır?
jww

Yanıtlar:


124

Satırları ayırt etmenin bir yolunu bulmalısın. Yorumunuza göre, bunun için özel rowid sütununu kullanabilirsiniz .

En düşük tutarak çiftleri silmek için rowidper (hash,d):

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

SQLite, birincil anahtar sütunu eklemenize izin vermiyor, değil mi?
Yamalar

sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
Yamalar

İlginç! İhtiyacınız olan kısım autoincrementyine de, primary keykısmı atlarsanız işe yarıyor mu?
Andomar

sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error Düzenleme: SQLite, otomatik olarak orada olan "rowid" sözde sütun türüne sahip bir şey var, bunu kullanabilir miyim?
Yamalar

1
delete from dist where rowid not in (select max(rowid) from dist group by hash); Hile yapıyor gibi görünüyor! Teşekkürler.
Yamalar

5

Sanırım en hızlısı bunun için veritabanını kullanmak olacaktır: aynı sütunlara sahip yeni bir tablo ekleyin, ancak uygun kısıtlamalarla (karma / gerçek çift üzerinde benzersiz bir dizin mi?), Orijinal tabloyu yineleyin ve kayıtları eklemeye yeni tablo, kısıtlama ihlali hatalarını göz ardı ederek (yani, istisnalar ortaya çıktığında yinelemeye devam edin).

Ardından eski tabloyu silin ve yenisini eskisiyle yeniden adlandırın.


Sadece tabloyu değiştirmek kadar zarif değil, sanırım, AMA yaklaşımınızla ilgili gerçekten iyi bir şey, sonuçlardan kesinlikle memnun olana kadar kaynak verilere dokunmadan / yok etmeden onu istediğiniz kadar tekrar çalıştırabilmenizdir. .
Adrian K

1

Birincil anahtar eklemek bir seçenek değilse, bu durumda bir yaklaşım, yinelenen DISTINCT'i geçici bir tabloda depolamak, mevcut tablodan yinelenen tüm kayıtları silmek ve ardından kayıtları geçici tablodan orijinal tabloya geri eklemek olacaktır. .

Örneğin (SQL Server 2008 için yazılmıştır, ancak teknik herhangi bir veritabanı için aynıdır):

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'ın bir ROW_NUMBER()tür işlevi olup olmadığından emin değilim , ancak varsa, burada listelenen yaklaşımlardan bazılarını da deneyebilirsiniz: Birincil anahtar olmadan bir SQL tablosundan yinelenen kayıtları silin


+1, delete <alias> from <table> <alias>
sqlite'ın
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.