НАПОМИНАЮ, ЧТО ПЕРЕД ТЕМ, КАК ВЫ БУДЕТЕ ЧТО-ТО ДЕЛАТЬ С РАБОЧЕЙ БД ОБЯЗАТЕЛЬНО НУЖНО СДЕЛАТЬ ЕЁ БЭКАП!
Я совсем недавно стал практиковаться с 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
Статья будет корректироваться, вполне возможно, что я в ней что-то упустил.