Suppression des lignes dupliquées de la base de données sqlite

91

J'ai une énorme table - 36 millions de lignes - dans SQLite3. Dans ce très grand tableau, il y a deux colonnes:

  • hash - texte
  • d - réel

Certaines des lignes sont des doublons. Autrement dit, les deux hashet dont les mêmes valeurs. Si deux hachages sont identiques, les valeurs de d. Cependant, deux identiques dn'impliquent pas deux identiques hash.

Je souhaite supprimer les lignes en double. Je n'ai pas de colonne de clé primaire.

Quel est le moyen le plus rapide de le faire?

Patchs
la source
Veuillez placer les réponses dans les blocs de réponse. Plus tard, vous pourrez accepter votre propre réponse. Voir également Comment l'acceptation d'une réponse fonctionne-t-elle?
jww

Réponses:

121

Vous avez besoin d'un moyen de distinguer les lignes. En fonction de votre commentaire, vous pouvez utiliser la colonne rowid spéciale pour cela.

Pour supprimer les doublons en conservant le plus bas rowidpar (hash,d):

delete   from YourTable
where    rowid not in
         (
         select  min(rowid)
         from    YourTable
         group by
                 hash
         ,       d
         )
Andomar
la source
SQLite ne vous permet pas d'ajouter une colonne de clé primaire, n'est-ce pas?
Correctifs du
sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
Correctifs du
Intéressant! La pièce dont vous avez besoin est la autoincrementbonne, est-ce que cela fonctionne si vous omettez la primary keypièce?
Andomar
sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error Edit: SQLite a un truc de type pseudo-colonne "rowid" qui est automatiquement là, puis-je l'utiliser?
Correctifs du
1
delete from dist where rowid not in (select max(rowid) from dist group by hash); Semble faire l'affaire! Merci.
Correctifs du
5

Je suppose que le plus rapide serait d'utiliser la base de données même pour cela: ajoutez une nouvelle table avec les mêmes colonnes, mais avec des contraintes appropriées (un index unique sur le hachage / paire réelle?), Parcourez la table d'origine et essayez d'insérer des enregistrements dans la nouvelle table, en ignorant les erreurs de violation de contrainte (c'est-à-dire continuer à itérer lorsque des exceptions sont déclenchées).

Supprimez ensuite l'ancienne table et renommez la nouvelle par l'ancienne.

MaDa
la source
Pas aussi élégant que de simplement modifier la table, je suppose, MAIS une très bonne chose à propos de votre approche est que vous pouvez la réexécuter autant de fois que vous le souhaitez sans toucher / détruire les données source jusqu'à ce que vous soyez absolument satisfait des résultats .
Adrian K
1

Si l'ajout d'une clé primaire n'est pas une option, une approche serait de stocker les doublons DISTINCT dans une table temporaire, de supprimer tous les enregistrements dupliqués de la table existante, puis de rajouter les enregistrements dans la table d'origine à partir de la table temporaire .

Par exemple (écrit pour SQL Server 2008, mais la technique est la même pour n'importe quelle base de données):

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

Je ne sais pas si sqlite a une ROW_NUMBER()fonction de type, mais si c'est le cas, vous pouvez également essayer certaines des approches répertoriées ici: Supprimer les enregistrements en double d'une table SQL sans clé primaire

rsbarro
la source
+1, delete <alias> from <table> <alias>
je