Eliminazione di righe duplicate dal database sqlite


91

Ho una tabella enorme - 36 milioni di righe - in SQLite3. In questa tabella molto grande, ci sono due colonne:

  • hash - testo
  • d - vero

Alcune delle righe sono duplicati. Cioè, entrambi hashe dhanno gli stessi valori. Se due hash sono identici, lo sono anche i valori di d. Tuttavia, due identici dnon implicano due identici hash.

Voglio eliminare le righe duplicate. Non ho una colonna chiave primaria.

Qual è il modo più veloce per farlo?


Si prega di inserire le risposte nei blocchi di risposte. Successivamente potrai accettare la tua risposta. Vedi anche Come funziona accettare una risposta?
jww

Risposte:


121

Hai bisogno di un modo per distinguere le righe. In base al tuo commento, potresti utilizzare la colonna speciale rowid per questo.

Per eliminare i duplicati mantenendo il valore più basso rowidper (hash,d):

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

SQLite non ti consente di aggiungere una colonna chiave primaria, vero?
Patch

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

Interessante! La parte di cui hai bisogno è autoincrementperò, funziona se la ometti primary key?
Andomar

sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error Modifica: SQLite ha un tipo di pseudo colonna "rowid" che si trova automaticamente lì, posso usarlo?
Patch

1
delete from dist where rowid not in (select max(rowid) from dist group by hash); Sembra fare il trucco! Grazie.
Patch del

5

Immagino che il più veloce sarebbe usare il database stesso per questo: aggiungi una nuova tabella con le stesse colonne, ma con i vincoli appropriati (un indice univoco sulla coppia hash / reale?), Ripeti la tabella originale e prova a inserire i record in la nuova tabella, ignorando gli errori di violazione dei vincoli (cioè continuare a iterare quando vengono sollevate eccezioni).

Quindi elimina la vecchia tabella e rinomina la nuova in quella vecchia.


Non così elegante come semplicemente alterare la tabella, immagino, MA una cosa davvero buona del tuo approccio è che puoi rieseguirlo tutte le volte che vuoi senza toccare / distruggere i dati di origine finché non sei assolutamente soddisfatto dei risultati .
Adrian K

1

Se l'aggiunta di una chiave primaria non è un'opzione, un approccio sarebbe quello di memorizzare i duplicati DISTINCT in una tabella temporanea, eliminare tutti i record duplicati dalla tabella esistente, quindi aggiungere nuovamente i record nella tabella originale dalla tabella temporanea .

Ad esempio (scritto per SQL Server 2008, ma la tecnica è la stessa per qualsiasi database):

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

Non sono sicuro che sqlite abbia una ROW_NUMBER()funzione di tipo, ma se lo fa potresti anche provare alcuni degli approcci elencati qui: Elimina i record duplicati da una tabella SQL senza una chiave primaria


+1, non sono sicuro che sqlite supporti la delete <alias> from <table> <alias>sintassi
Andomar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.