web-dev-qa-db-fra.com

Quel est le meilleur moyen de dédupliquer une table?

J'ai déjà vu quelques solutions à ce problème, mais je me demande quel est le moyen le plus efficace et le plus efficace de dupliquer un tableau. Vous pouvez utiliser du code (SQL, etc.) pour illustrer votre propos, mais je ne cherche que des algorithmes de base. J'ai supposé qu'il y aurait déjà une question à ce sujet sur SO, mais je n'ai pas pu en trouver une, donc si elle existe déjà, il suffit de me prévenir.

(Juste pour clarifier, je parle de la suppression des doublons dans une table qui a une PK incrémentielle automatique et certaines lignes qui sont des doublons dans tout sauf le champ PK.)

28
froadie

SELECT DISTINCT <insert all columns but the PK here> FROM foo. Créez une table temporaire à l'aide de cette requête (la syntaxe varie en fonction du SGBDR, mais il existe généralement un modèle SELECT … INTO ou CREATE TABLE AS disponible), puis supprimez l'ancienne table et y pompez les données.

11
Hank Gay

Utilisation de la fonction analytique numéro_ligne:

WITH CTE (col1, col2, dupcnt)
AS
(
SELECT col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col1) AS dupcnt
FROM Youtable
)
DELETE
FROM CTE
WHERE dupcnt > 1
GO                                                                 
8
Katherine

La déduplication est rarement simple. En effet, les enregistrements à dédoubler ont souvent des valeurs légèrement différentes dans certains champs. Par conséquent, choisir l’enregistrement à conserver peut poser problème. De plus, les dupes sont souvent des enregistrements de personnes et il est difficile de déterminer si les deux John Smith sont deux personnes ou une personne dupliquée. Passez donc beaucoup de temps (50% ou plus du projet dans son ensemble) à définir ce qui constitue un duper et à gérer les différences et les enregistrements enfants. 

Comment savez-vous quelle est la valeur correcte? La déduplication supplémentaire nécessite que vous gériez tous les enregistrements enfants qui ne sont orphelins. Que se passe-t-il lorsque vous constatez qu'en modifiant l'id de l'enregistrement enfant, vous violez soudainement l'un des index ou contraintes uniques - cela se produira à terme et votre processus devra le gérer. Si vous avez bêtement choisi d'appliquer toutes vos contraintes uniquement à l'application, vous pouvez même ne pas savoir que les contraintes sont violées. Lorsque vous avez 10 000 enregistrements à dédoubler, vous ne pouvez pas utiliser l’application pour effectuer la déduction un à la fois. Si la contrainte n'est pas dans la base de données, vous aurez beaucoup de chance de préserver l'intégrité des données lors de la déduplication.

Une complication supplémentaire est que les dupes ne correspondent pas toujours exactement sur le nom ou l'adresse. Par exemple, un représentant nommé Joan Martin peut être un duper d'un représentant commercial nommé Joan Martin-Jones, en particulier s'il a la même adresse et le même courrier électronique. OR vous pourriez avoir John ou Johnny dans le nom. Ou la même adresse civique sauf un enregistrement abrégé ST. et un épelé rue. Dans SQL Server, vous pouvez utiliser SSIS et le regroupement fuzzy pour identifier également les correspondances proches. Ce sont souvent les dups les plus communs car le fait qu'ils ne soient pas des correspondances exactes explique pourquoi ils ont été qualifiés de dups.

Pour certains types de déduplication, vous aurez peut-être besoin d'une interface utilisateur, de sorte que la personne effectuant la déduplication puisse choisir laquelle des deux valeurs utiliser pour un champ particulier. Cela est particulièrement vrai si la personne à dédoubler joue deux ou plusieurs rôles. Il se peut que les données d'un rôle particulier soient généralement meilleures que celles d'un autre rôle. Ou il se peut que seuls les utilisateurs sachent avec certitude quelle est la valeur correcte ou qu’ils aient besoin de contacter des personnes pour savoir s’il s’agit vraiment de dupes ou tout simplement de deux personnes portant le même nom. 

6
HLGEM

Ajout du code actuel ici pour référence future 

Donc, il y a 3 étapes, et donc 3 instructions SQL:

Étape 1: Déplacez les non-doublons (tuples uniques) dans une table temporaire

CREATE TABLE new_table as
SELECT * FROM old_table WHERE 1 GROUP BY [column to remove duplicates by];

Étape 2: supprimez l’ancienne table (ou renommez-la) Nous n’avons plus besoin de la table avec toutes les entrées en double, alors supprimez-la!

DROP TABLE old_table;

Étape 3: renommez la new_table avec le nom de la old_table

RENAME TABLE new_table TO old_table;

Et bien sûr, n'oubliez pas de corriger votre code de bug pour ne plus insérer de doublons!

6
DropHit

Voici la méthode que j'utilise si vous pouvez obtenir vos critères de dupe dans une déclaration groupe par et que votre table comporte une colonne d'identité id pour l'unicité:

delete t
from tablename t
inner join  
(
    select date_time, min(id) as min_id
    from tablename
    group by date_time
    having count(*) > 1
) t2 on t.date_time = t2.date_time
where t.id > t2.min_id

Dans cet exemple, date_time correspond aux critères de regroupement. Si vous avez plusieurs colonnes, veillez à les joindre toutes.

3
DShook

Je prends celui de DShook et donne un exemple de déduplication dans lequel vous ne garderiez que l'enregistrement avec la date la plus élevée. 

Dans cet exemple, disons que j'ai 3 enregistrements, tous avec le même app_id, et que je veux seulement garder celui avec la date la plus élevée:

DELETE t
FROM @USER_OUTBOX_APPS t
INNER JOIN  
(
    SELECT 
         app_id
        ,max(processed_date) as max_processed_date
    FROM @USER_OUTBOX_APPS
    GROUP BY app_id
    HAVING count(*) > 1
) t2 on 
    t.app_id = t2.app_id
WHERE 
    t.processed_date < t2.max_processed_date
2
Taylor Brown

Pour ceux d'entre vous qui préfèrent une approche rapide et incorrecte, il suffit de répertorier toutes les colonnes qui définissent ensemble un enregistrement unique et de créer un index unique avec ces colonnes, comme suit:

ALTER IGNORE TABLE TABLE_NAME AJOUTER UNIQUE (column1, column2, column3)

Vous pouvez supprimer les mots-clés d'index uniques.

1
Demian Perry

Cela peut dédupler les valeurs dupliquées dans c1:

select * from foo
minus
select f1.* from foo f1, foo f2
where f1.c1 = f2.c1 and f1.c2 > f2.c2
0
Jim X.

Vous pouvez générer un hachage pour chaque ligne (à l'exclusion de la PC), le stocker dans une nouvelle colonne (ou, si vous ne pouvez pas ajouter de nouvelles colonnes, pouvez-vous déplacer le tableau dans une zone d'activation temporaire?), Puis rechercher toutes les autres lignes avec le même hash. Bien entendu, vous devez pouvoir vous assurer que votre fonction de hachage ne produit pas le même code pour différentes lignes.

Si deux lignes sont en double, est-ce que vous vous en débarrassez? Est-il possible que d'autres données dépendent des deux doublons? Si tel est le cas, vous devrez passer par quelques étapes:

  • Trouvez les dupes
  • Choisissez l’un d’eux comme dupeA pour éliminer
  • Trouver toutes les données dépendant de dupeA
  • Modifiez ces données pour faire référence à dupeB
  • supprimer dupeA.

Cela peut être facile ou compliqué, selon votre modèle de données existant.

Tout ce scénario ressemble à un projet de maintenance et de refonte. Si oui, bonne chance !!

Pour SQL, vous pouvez utiliser la table INSERT IGNORE INTO SELECT xy FROM unkeyed_table;

Pour un algorithme, si vous pouvez supposer que les clés to-be-primary peuvent être répétées, mais qu'une clé to-be-primary-identifie de manière unique le contenu de la ligne, puis hachez uniquement la clé to-be-primary et vérifiez la répétition .

0
ron

Je pense que cela ne devrait nécessiter rien de plus qu'un simple regroupement de toutes les colonnes, à l'exception de l'id, et le choix d'une ligne sur chaque groupe. Pour simplifier, ne placez que la première ligne, mais cela n'a pas d'importance, car vous avez des contraintes supplémentaires sur l'id.

Ou l’inverse pour se débarrasser des lignes ... il suffit de supprimer toutes les lignes et d’en accepter une seule de tous les groupes.

0
Daniel Brückner

En voici un que j'ai rencontré dans la vraie vie.

Supposons que vous avez un tableau des connexions externes/tierces pour les utilisateurs, que vous allez fusionner deux utilisateurs et que vous souhaitez dédupliquer les valeurs de fournisseur/fournisseur.

    ;WITH Logins AS
    (
        SELECT [LoginId],[UserId],[Provider],[ProviderKey]
        FROM [dbo].[UserLogin] 
        WHERE [UserId]=@FromUserID -- is the user we're deleting
              OR [UserId]=@ToUserID -- is the user we're moving data to
    ), Ranked AS 
    (
        SELECT Logins.*
            , [Picker]=ROW_NUMBER() OVER (
                       PARTITION BY [Provider],[ProviderKey]
                       ORDER BY CASE WHEN [UserId]=@FromUserID THEN 1 ELSE 0 END)
        FROM Logins
    )
    MERGE Logins AS T
    USING Ranked AS S
    ON S.[LoginId]=T.[LoginID]
    WHEN MATCHED AND S.[Picker]>1 -- duplicate Provider/ProviderKey
                 AND T.[UserID]=@FromUserID -- safety check 
    THEN DELETE
    WHEN MATCHED AND S.[Picker]=1 -- the only or best one
                 AND T.[UserID]=@FromUserID
    THEN UPDATE SET T.[UserID]=@ToUserID
    OUTPUT $action, DELETED.*, INSERTED.*;
0
IDisposable

Pour dédupliquer/dédupliquer/supprimer la duplication/supprimer les lignes répétées/重 重/重复 记录, il existe plusieurs façons.

  1. Si les lignes dupliquées sont exactement les mêmes, utilisez group by 

    créer la table TABLE_NAME_DEDUP
    as select colonne1, colonne2, ... (tous les noms de colonnes) de TABLE_NAME groupe par colonne1, colonne2, - tous les noms de colonnes

Alors TABLE_NAME_DEDUP est la table dédupliquée.

Par exemple,

create table test (t1 varchar(5), t2 varchar(5));
insert into test  values ('12345', 'ssdlh');
insert into test  values ('12345', 'ssdlh');
create table test_dedup as
select * from test 
group by t1, t2;
-----optional
--remove original table and rename dedup table to previous table
--this is not recommend in dev or qa. DROP table test; Alter table test_dedup rename to test;
  1. Vous avez un rowid, le rowid a été dupliqué, mais les autres colonnes sont différentes. la duplication

    crée la table test_dedup asselect column1, column2, ... (tous les noms de colonnes) from ( select * , row_number () over (partition by rowid order by column1, column2, .. . (Tous les noms de colonnes sauf rowid)) en tant que cn from test ) où cn = 1

Cela utilise la fonctionnalité qui lorsque vous utilisez order by, la valeur null sera ordonnée derrière la valeur non-null.

create table test (rowid_ varchar(5), t1 varchar(5), t2 varchar(5));
insert into test  values ('12345', 'ssdlh', null);
insert into test  values ('12345', 'ssdlh', 'lhbzj');
create table test_dedup as
select rowid_, t1, t2 from
(select *
  , row_number() over (partition by rowid_ order by t1, t2) as cn
  from  test)
 where cn =1
 ;

-----optional
--remove original table and rename dedup table to previous table
--this is not recommend in dev or qa. DROP table test; Alter table test_dedup rename to test;
0
Decula

Ces méthodes fonctionneront, mais sans un identifiant explicite en tant que clé PK, il sera alors difficile de déterminer quelles lignes supprimer. Le rebond dans une table temporaire supprimer de l'original et ré-insérer sans les dupes semble être le plus simple.

0
JohnnC_Bravo_inTX