2011-11-18 22 views
75

Ho una tabella enorme - 36 milioni di righe - in SQLite3.Eliminazione di righe duplicate dal database sqlite

In questo tavolo molto grande, ci sono due colonne

  • hash - testo
  • d - reale

Tuttavia, alcune delle righe sono duplicati. Cioè, sia hash che d hanno gli stessi valori.

Inoltre, se due hash sono identici, così sono i valori di D, ma due ds identici non implica due hash identici

Ad ogni modo, voglio eliminare le righe duplicate. Non ho una colonna chiave primaria. Qual è il modo più veloce per farlo?


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

sembra fare il trucco.

+2

+1 il tuo 'EDIT' ha risparmiato un sacco di tempo ... :) – Ankur

+0

Accetto. @Patches EDIT funziona direttamente per me –

+1

Devi amare i commenti auto-consapevoli: "Non ho una colonna chiave primaria perché sono un idiota" :) – dwanderson

risposta

94

È necessario un modo per distinguere le righe. In base al tuo commento, potresti utilizzare lo speciale rowid column per quello.

per eliminare i duplicati, mantenendo il più basso rowid per (hash,d):

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

SQLite non consente di aggiungere una colonna chiave primaria, vero? – Patches

+0

'sqlite> alter table dist add id intero autoincrement chiave primaria; Errore: impossibile aggiungere una colonna PRIMARY KEY' – Patches

+0

Interessante! La parte di cui hai bisogno è "autoincrement", però, funziona se ometti la parte "chiave primaria"? – Andomar

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 e quindi aggiungere nuovamente i record nella tabella originale dalla tabella temporanea.

Per 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 

io non sono sicuro se SQLite ha una funzione ROW_NUMBER() tipo, ma se lo fa si poteva provare anche alcuni degli approcci elencati qui: Delete duplicate records from a SQL table without a primary key

+0

+1, non sono sicuro che sqlite supporti l'eliminazione ' da

'syntax though – Andomar

4

immagino il più veloce sarebbe quella di utilizzare il database molto per esso: aggiungere una nuova tabella con le stesse colonne, ma con i vincoli adeguati (un indice univoco su hash/coppia reale?), scorrere la tabella originale e provare a inserire i record nella nuova tabella, ignorando gli errori di violazione dei vincoli (ad es. continua la iterazione quando vengono sollevate le eccezioni).

Quindi eliminare la vecchia tabella e rinominare il nuovo con quello precedente.

+0

Non è elegante come semplicemente alterare il tavolo, suppongo, ma una cosa davvero buona del tuo approccio è che puoi ri-eseguirlo tutte le volte che vuoi senza toccare/distruggere i dati di origine finché non sei assolutamente soddisfatto risultati. –

Problemi correlati