6
votes

SQL Query - Supprimer des doublons si plus de 3 DUPS?

Quelqu'un a-t-il une instruction SQL élégante pour supprimer des enregistrements en double d'une table, mais uniquement s'il y a plus de x nombre de doublons? Donc, il permet jusqu'à 2 ou 3 doublons, mais c'est tout?

J'ai actuellement une instruction SELECT qui effectue les suivantes: P>

delete table
from table t
left outer join (
 select max(id) as rowid, dupcol1, dupcol2
 from table
 group by dupcol1, dupcol2
) as keeprows on t.id=keeprows.rowid
where keeprows.rowid is null


1 commentaires

Quand il y a 5 duplicats, ne voulez-vous que quelques-uns à gauche après la suppression ou trois?


4 Réponses :


3
votes

avoir est votre ami

Sélectionnez ID, comptez (*) CNT à partir du groupe de table par ID ayant CNT> 2


0 commentaires

7
votes
with cte as (
  select row_number() over (partition by dupcol1, dupcol2 order by ID) as rn
     from table)
delete from cte
   where rn > 2; -- or >3 etc
The query is manufacturing a 'row number' for each record, grouped by the (dupcol1, dupcol2) and ordered by ID. In effect this row number counts 'duplicates' that have the same dupcol1 and dupcol2 and assigns then the number 1, 2, 3.. N, order by ID. If you want to keep just 2 'duplicates', then you need to delete those that were assigned the numbers 3,4,.. N and that is the part taken care of by the DELLETE.. WHERE rn > 2; Using this method you can change the ORDER BY to suit your preferred order (eg.ORDER BY ID DESC), so that the LATEST has rn=1, then the next to latest is rn=2 and so on. The rest stays the same, the DELETE will remove only the oldest ones as they have the highest row numbers. Unlike this closely related question, as the condition becomes more complex, using CTEs and row_number() becomes simpler. Performance may be problematic still if no proper access index exists.

5 commentaires

Merci Remus, mais comme je ne suis pas un expert SQL et non familiers avec des mots-clés spécifiques en 2005, pourriez-vous m'expliquer quelle est la requête? Je suppose que la partition est un joli raccourci pour une jonction de gauche à une table groupée, semblable à mon premier exemple ?? Votre deuxième ligne renvoie donc un nouvel identifiant de tous les enregistrements en double en fonction des colonnes fournies? Est-ce que le nombre de fois que la ligne avait été dupliqué sur la base des colonnes de la deuxième ligne? Merci.


La requête fabrique un "numéro de ligne" pour chaque enregistrement, groupé par (Dupcol1, Dupcol2) et commandé par ID. En effet, ce numéro de ligne compte 'DUPLICATES' qui ont le même DUPCOL1 et DUPCOL2 et attribue alors le nombre 1, 2, 3 .. n, commander par ID. Si vous voulez garder seulement 2 "doublons", alors vous devez supprimer ceux qui ont été attribués les numéros 3,4, .. N et c'est la partie prise en charge par le dellete .. Où rn> 2; HTH, laissez-moi savoir si on n'est toujours pas clair.


Nope, je gocha, merci beaucoup. Une dernière chose que cependant, je veux m'assurer que je garde toujours le dernier enregistrement. Donc, si je garde des enregistrements avec dire <2 doublons, puis jetez-le tous les autres, comment puis-je modifier la requête pour vous assurer que les deux ou trois enregistrements les plus récents (ID) de la table sont préservés. Par exemple: dites qu'un enregistrement est répertorié dans notre système 10 fois. Cela viole la règle duplicate "2". Nous aimerions retirer 7 des doublons, laissant un seul record principal et deux doublons. Par enregistrement principal, nous entendons le dernier enregistrement (le plus à jour) qui est entré dans le système.


Vous modifiez la commande en fonction de votre ordre préféré (par exemple, commander par Id ID desc), de sorte que le dernier ait RN = 1, puis le lendemain à la dernière est rn = 2 et ainsi de suite. Le reste reste le même, la suppression ne supprime que les plus anciennes car elles ont les numéros de rangée les plus élevés.


@Remus - Vos explications ont vraiment ajouté à la réponse, donc je les ai pénétrées là-bas.



0
votes

solution assez tard mais la plus simple pourrait être la suivante Supposons que nous ayons une table Emp_Dept (Empid, Deptid) qui a des lignes en double, Ici, j'ai utilisé @Count comme varibale .. E.g. 2 dupliqué autorisé alors @Count = 2 Sur la base de données Oracle

  delete from emp_dept where @@Count <= ( select count(1) from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.nid< emp_dept.nid ) 


0 commentaires

1
votes

Vous pouvez essayer la requête suivante:

DELETE FROM table t1 
WHERE rowid IN
(SELECT MIN(rowid) FROM table t2 GROUP BY t2.id,t2.name HAVING COUNT(rowid)>3);


0 commentaires