Могу ли я изменить идентификаторы внешнего ключа при удалении строки FK? - PullRequest
2 голосов
/ 24 июня 2009

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

Например, допустим, у нас есть следующие отношения:

-------------------   -------------------
*     Customer    *   *      Order      *
-------------------   -------------------
* ID              *   * ID              *
* Name            *   * CustomerID      *
* Address         *   * Item            *
-------------------   -------------------

Там довольно очевидные отношения - для заказа необходим идентификатор клиента, а это внешний ключ. Поэтому мы не можем удалить клиента и сохранить данные заказа.

В этом примере я полностью согласен с потерей избыточных данных о клиентах, но для дальнейшего использования я хотел бы изменить CustomerID с Order на ID клиента для строки «Удаленный клиент».

Есть ли способ сказать «удалите это, и если есть ограничения внешнего ключа, замените CustomerID вместо этого идентификатора»? БД - MS SQL 2005.

Ответы [ 6 ]

4 голосов
/ 24 июня 2009

Я бы сказал:

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

-------------
*  Dupes    *
-------------
* del_id    *
* keep_id   *
-------------

шаг 2: пересвязать заказы

update order o
set CustomerID=(select keep_id from Dupes d where d.del_id=o.CustomerID)
where CustomerID in (select del_id from Dupes)

шаг 3: удалить старых клиентов

delete from Customer
where ID in (select del_id from Dupes)

И вуаля.

1 голос
/ 24 июня 2009

Вы говорите, что у вас есть дубликаты записей о клиентах, т. Е. Данные клиентов совпадают, однако идентификатор клиента отличается, и поэтому существуют заказы, которые ссылаются на несколько версий одного и того же клиента?

Если это так, я бы выполнил упражнение по очистке данных .

Создание / построение справочной таблицы со столбцами

  • CustomerID
  • OrderID
  • PrimaryCustomerID - (необходимо рассчитать)

Затем можно выполнить обновление таблицы «Заказы», ​​чтобы гарантировать, что каждый заказ ссылается только на PrimaryCustomerID.

Затем вы можете удалить записи Клиента, на которые больше нет ссылок в Заказе (т.е. они являются дубликатами). В качестве альтернативы вы можете добавить атрибут в таблицу Customer, чтобы пометить записи, а не удалить их (т. Е. DuplicateFlag или isDeleted).

Надеюсь, это имеет смысл.

1 голос
/ 24 июня 2009

В любом случае, у вас должно быть два идентификатора: dupCustomerId и newCustomerId, так почему бы вам сначала не обновить ссылку?

UPDATE Order set CustomerID = newCustomerId WHERE CustomerID = dupCustomerId

А затем удалите дубликат из таблицы клиентов:

DELETE from Customer WHERE ID = dupCustomerId

Или я что-то здесь упускаю?

1 голос
/ 24 июня 2009

Вы можете использовать триггер удаления в таблице клиентов. Книги в сети при создании триггера.

Но почему бы вам не обновить записи заказов, прежде чем удалять клиентов? Это проще, избегает спусковых механизмов боли, и IMO будет держать логику в том же месте.

1 голос
/ 24 июня 2009

AFAIK, это нельзя сделать одним оператором SQL.

Но это звучит как честная игра для триггера ПЕРЕД УДАЛЕНИЕМ на КЛИЕНТЕ.

Вам просто нужно убедиться, что две операции были одной единицей работы.

0 голосов
/ 24 июня 2009

Мы создали инструмент дедупликации (как и вы), который сначала ищет места, где есть конфликты данных (например, два разных телефонных номера), и позволяет человеку, выполняющему дедупликацию, выбрать правильные данные. Затем инструмент меняет идентификатор на тот, который вы храните, начиная с самой нижней дочерней таблицы и просматривая все связанные таблицы. Как только все ссылки на удаляемую запись удаляются, она удаляет родительскую запись. Отключение обычно представляет собой сложный процесс, и этот инструмент должен быть тщательно спроектирован для обработки того, что должно быть обработано, и для внесения изменений в инструмент по мере добавления новых таблиц внешнего ключа. Вы можете настроить его так, чтобы alawys выбирал информацию в записи, которую вы храните, когда у вас возникают конфликты данных, но обычно это плохая идея, если вы не вмешиваетесь вручную. Это потому, что вам часто нужен вклад кого-то, кто знает клиентов. В противном случае вы можете заменить хороший адрес на плохой. Вот общий сценарий того, как дуп попал туда в первую очередь. Клиент А был клиентом некоторое время и имеет несколько заказов. Он идет, чтобы заказать agin, и заказчик запрашивает его номер телефона или другую информацию, позволяющую найти его. Клиент А недавно переехал и получил новый номер телефона и адрес, поэтому он не найден и создана новая запись. Позже выясняется, что это дублирование, но автоматический процесс дедупликации выбирает более старую запись, потому что у нее больше заказов и, таким образом, заменяет запись на текущий новый адрес и телефон. Клиент звонит, чтобы заказать снова, и создается еще одно дублирование, потому что заказчик снова не может его найти. Вот почему я чувствую, что дедупликация должна быть частично ручным процессом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...