НАПОМИНАЮ, ЧТО ПЕРЕД ТЕМ, КАК ВЫ БУДЕТЕ ЧТО-ТО ДЕЛАТЬ С РАБОЧЕЙ БД ОБЯЗАТЕЛЬНО НУЖНО СДЕЛАТЬ ЕЁ БЭКАП!

Я совсем недавно стал практиковаться с SQL и, начал осознавать, что многие рутинные задачи манипулирования данными можно решить посредством паттернов (шаблонов). Другими словами, например, если стоит задача избавиться от дублирующихся записей в какой-либо таблице, нет необходимости каждый раз «изобретать велосипед», достаточно взять за основу шаблон кода, немного переписать его под нужную таблицу и скрипт избавления от дубликатов готов.

Данное решение мне показал мой наставник по SQL — Ильнур, и я решил увековечить его в своем блоге.

Для примера в этой статье я буду рассматривать поиск дубликатов-сотрудников, в таблице T_WORKER, перепривязку всех внешних ключей на одного из сотрудника-дубликата, с целью оставить одного из дубликатов полностью без зависимых записей в других таблицах, и дальнейшее удаление всех сотрудников-дубликатов, оставив из каждой дублирующейся записи только одну. Следующий скрипт:

if object_id('tempdb..#tmpid') is not null
     drop table #tmpid

--следующая конструкция собирает набор идентификаторов для перепривязки внешних ключей в зависимых таблицах
;with t_worker_DUBLS as
(
select ROW_NUMBER() over(PARTITION by t1.Lastname, t1.FirstName, t1.FatherName order by t1.WorkerID desc) as rn,* from AKUZ.t_worker t1
)
select t1.WorkerID as WorkerID_Old, t1_dub.WorkerID as WorkerID_New
into #tmpid
from AKUZ.t_worker t1
join t_worker_DUBLS t1_dub
on t1_dub.Lastname = t1.Lastname and t1_dub.FirstName = t1.FirstName and t1_dub.FatherName = t1.FatherName and t1.WorkerID <> t1_dub.WorkerID
where t1_dub.rn = 1

--перепривязка внешних ключей в зависимых таблицах (т.е. все записи на сотрудника-дубликата перепривяжутся на одного из сотрудинков-дубликатов, с целью осободить для удаления другого сотрдуника-дубликата)
update t1
set t1.Worker = t.WorkerID_New
from AKUZ.T_POST t1
join #tmpid t
     on t.WorkerID_Old = t1.Worker

update t1
set t1.Worker = t.WorkerID_New
from AKUZ.T_WORKER_HOLIDAY t1
join #tmpid t
     on t.WorkerID_Old = t1.Worker

update t1
set t1.Worker = t.WorkerID_New
from AKUZ.T_STATE_POST t1
join #tmpid t
     on t.WorkerID_Old = t1.Worker

update t1
set t1.Worker = t.WorkerID_New
from AKUZ.T_NURSING_CHILD_HISTORY t1
join #tmpid t
     on t.WorkerID_Old = t1.Worker

--Удаляем сотрудников-дубликатов, на них больше ничто не ссылается
delete t1
from AKUZ.t_worker t1
where exists (select * from #tmpid t where t1.WorkerID = t.WorkerID_Old)

--Удаляем временную таблицу
drop table #tmpid

Этот код можно взять за шаблон для поиска и удаления дублирующихся записей в различных таблицах и так как мы можем автоматизировать сборку этого кода с помощью динамического SQL, я написал скрипт, который на основе некоторых входных данных сам генерирует готовый скрипт для удаления записей-дубликатов.

Template_Removal_Of_Dublicates.zip

Статья будет корректироваться, вполне возможно, что я в ней что-то упустил.