Procédure SQL: suppression des duplicates, réaffectation des references de key étrangère

Je travaille pour une entreprise qui gère des compétitions classées.

Malheureusement, leur table de membre n'a aucune contrainte unique sur les courriels, et certains users ont créé un nouveau count avec le même courriel pour chaque course ou équipe dans laquelle ils se trouvent.

Je veux placer une contrainte unique sur la colonne pour éviter toute duplication dans le futur, mais …

Le problème: Comment puis-je supprimer les duplicates avec une seule requête sans perdre datatables qui leur sont connectées?

Je pense que cela a quelque chose à voir avec la mise à jour de toutes les foreign keys pour correspondre à une instance d'un user, puis la suppression des duplicates.

Clarification: Dans l'exemple ci-dessous, les lignes marquées se réfèrent aux membres en double avec les ID: 03, 04, 05 et 06. Dans ce cas, la solution serait:

  1. Les references de key étrangère avec les ID 03 et 05 ont été remplacées par 01.
  2. Les references de key étrangère avec les ID 04 et 06 ont été remplacées par 02.
  3. Dupliquer les membres avec les ID 03, 04, 05 et 06 supprimés.

Mais comment cela peut-il être fait dans MSSQL?

Member table ID | Username | Gender | Email 01 | User1 | Male | [email protected] 02 | User2 | Female | [email protected] *03 | User3 | Male | [email protected] *04 | User4 | Female | [email protected] *05 | User5 | Male | [email protected] *06 | User6 | Female | [email protected] MemberToTeam table MemberID_fk | TeamID_fk 01 | 01 02 | 01 *03 | 02 *04 | 02 *05 | 03 *06 | 03 RaceRank table RaceID_fk | MemberID_fk | Ranking 01 | 01 | 12 01 | 02 | 1 *02 | 03 | 5 *02 | 04 | 7 *03 | 05 | 4 *03 | 06 | 9 

Merci de votre aide.

Cela le fait dans une requête. Répétez pour l'autre table.

 with FAKES as ( select Email from Member group by Email having count(id) >1 ), FAKE_ID as ( select id, email, row_number() over(partition by email order by id) as c_id from Member where email in (select Email from FAKES) ) , DEDUP as ( select fi.id, f2.id as val_id from FAKE_ID fi inner join FAKE_ID f2 on fi.email = f2.email where fi.c_id > 1 and f2.c_id = 1 ) update mt set mt.MemberID_fk = dd.val_id from MemberToTeam mt inner join DEDUP dd on dd.id = mt.MemberID_fk; 

Testé ici

Ce code résoudra le problème

 --MemberToTeam ;with cte_dupes as ( select ID,Email, row_number() over (partition by Email order by Email) rn from Member ) update mt set MemberID_fk = (select cte.ID from cte_dupes cte where rn=1 and cte.Email = m.Email) from MemberToTeam mt inner join Member m on m.ID = mt.MemberID_fk inner join cte_dupes cte on cte.ID = mt.MemberID_fk and cte.rn > 1; --RaceRank ;with cte_dupes as ( select ID,Email, row_number() over (partition by Email order by Email) rn from Member ) update r set MemberID_fk = (select cte.ID from cte_dupes cte where rn=1 and cte.Email = m.Email) from RaceRank r inner join Member m on m.ID = r.MemberID_fk inner join cte_dupes cte on cte.ID = r.MemberID_fk and cte.rn > 1; 

Vous devrez probablement mettre à jour toutes les autres tables qui sont liées, via une key étrangère, à la table des membres.

Vous pouvez choisir un seul logging sur lequel s'appuyer dans la table des membres, parmi tous les loggings qui partagent la même adresse e-mail, puis mettre à jour les tables liées avec une requête comme celle-ci:

 update myreferencetable set memberid = [the single instance of the member] where memberid in (select memberid from member where email = [email address with duplicates]