2011-11-18 39 views
75

Tengo una gran tabla (36 millones de filas) en SQLite3.Supresión de filas duplicadas de la base de datos sqlite

En esta mesa muy grande, hay dos columnas

  • de hash - texto
  • d - bienes

Sin embargo, algunas de las filas son duplicados. Es decir, tanto hash como d tienen los mismos valores.

Además, si dos valores hash son idénticos, por lo que son los valores de D, pero dos ds idénticos no implica dos hashes idénticos

De todos modos, quiero eliminar las filas duplicadas. No tengo una columna de clave principal. ¿Cuál es la forma más rápida de hacer esto?


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

parece hacer el truco.

+2

+1 su 'EDIT' me ha ahorrado mucho tiempo ... :) – Ankur

+0

De acuerdo. @Patches EDIT funciona directamente para mí –

+1

Me encantan los comentarios autoconscientes: "No tengo una columna de clave principal porque soy un idiota" :) – dwanderson

Respuesta

94

Necesita una forma de distinguir las filas. Según su comentario, puede usar el número especial rowid column para eso.

Para eliminar duplicados, manteniendo el más bajo rowid por (hash,d):

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

SQLite no le permite agregar una columna de clave principal, ¿o sí? – Patches

+0

'sqlite> alterar tabla dist add id integer clave primaria autoincrement; Error: No se puede agregar una columna PRIMARY KEY' – Patches

+0

¡Interesante! Sin embargo, la parte que necesitas es 'autoincrement', ¿funciona si omites la parte' primary key'? – Andomar

1

Si agregar una clave principal no es una opción, entonces un enfoque sería almacenar los duplicados DISTINCT en una tabla temporal, eliminar todos los registros duplicados de la tabla existente y luego agregar los registros a la tabla original de la mesa de temp.

Por ejemplo (escrito para SQL Server 2008, pero la técnica es la misma para cualquier base de datos):

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 

no estoy seguro de si SQLite tiene una función ROW_NUMBER() tipo, pero si lo hace usted podría Pruebe también algunos de los enfoques enumerados aquí: Delete duplicate records from a SQL table without a primary key

+0

+1, no estoy seguro si sqlite admite el 'eliminar de

'sintaxis aunque – Andomar

4

supongo que el más rápido sería utilizar la misma base de datos para que: añadir una nueva tabla con las mismas columnas, pero con restricciones apropiadas (¿un índice único en par hash/real?), itere a través de la tabla original e intente insertar registros en la nueva tabla, ignorando los errores de violación de restricciones (es decir, continúe iterando cuando se generan excepciones).

A continuación, elimine la tabla anterior y cambie el nombre de la nueva por la anterior.

+0

No es tan elegante como simplemente alterar la mesa, supongo, PERO una cosa realmente buena de su enfoque es que puede volver a ejecutarlo tantas veces como quiera sin tocar/destruir los datos de origen hasta que esté absolutamente satisfecho con el resultados. –

Cuestiones relacionadas