Как я могу объединить две избыточные записи в таблице MySQL, поддерживая все отношения PK / FK? - PullRequest
8 голосов
/ 08 марта 2011

Допустим, у меня есть таблица customers со следующими полями и записями:

id   first_name   last_name   email                  phone
------------------------------------------------------------------------
1    Michael      Turley      mturley@whatever.com   555-123-4567
2    John         Dohe        jdoe@whatever.com      
3    Jack         Smith       jsmith@whatever.com    555-555-5555
4    Johnathan    Doe                                123-456-7890

Есть несколько других таблиц, таких как orders, rewards, receipts, которые имеют внешние ключи customer_id, относящиеся к customers.id.

этой таблицы.

Как вы можете видеть, благодаря своей бесконечной мудрости, мои пользователи создали дубликаты записей для Джона Доу, с непоследовательным написанием и отсутствующими данными. Администратор замечает это, выбирает клиентов 2 и 4 и нажимает «Объединить». Затем им предлагается выбрать, какое значение является правильным для каждого поля и т. Д., И т. Д., И мой PHP определяет, что объединенная запись должна выглядеть следующим образом:

id   first_name   last_name   email                  phone
------------------------------------------------------------------------
?    John         Doe         jdoe@whatever.com      123-456-7890

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

Здесь я не уверен, что делать. Мой инстинкт должен сделать это:

DELETE FROM customers WHERE id = 4;

UPDATE customers
SET first_name = 'John',
    last_name  = 'Doe',
    email      = 'jdoe@whatever.com',
    phone      = '123-456-7890'
WHERE id = 2;

UPDATE orders, rewards, receipts
SET customer_id = 2
WHERE customer_id = 4;

Я думаю, что это сработало бы, но если позже я добавлю еще одну таблицу с внешним ключом customer_id, я должен не забыть вернуться и добавить эту таблицу ко второму запросу UPDATE в моей функции слияния или риску потери целостности .

Должен быть лучший способ сделать это.

Ответы [ 4 ]

6 голосов
/ 03 июня 2011

Я получил здесь от Google, это мои 2 цента:

SELECT `TABLE_NAME` 
FROM `information_schema`.`KEY_COLUMN_USAGE` 
WHERE REFERENCED_TABLE_SCHEMA='DATABASE'
  AND REFERENCED_TABLE_NAME='customers'
  AND REFERENCED_COLUMN_NAME='customer_id'

добавить БД для страховки (вы никогда не узнаете, когда кто-то скопирует БД).

Вместо того, чтобы смотретьдля имени столбца, здесь мы рассмотрим сами внешние ключи

Если вы измените ограничения на удаление, чтобы запретить, ничего нельзя удалить до удаления / переноса дочерних элементов

2 голосов
/ 08 марта 2011

Короткий ответ: нет, нет лучшего способа (о котором я могу думать).

Это компромисс.Если вы обнаружите, что таких экземпляров много, возможно, стоит потратить некоторое время на написание более надежного алгоритма проверки существующих клиентов перед добавлением нового (т. Е. Проверки вариантов по имени / фамилии, представления их тому, кто добавляетклиент, спрашивая его 2 или 3 раза, действительно ли они хотят добавить этого нового клиента и т. д.).Если таких примеров не много, возможно, не стоит инвестировать это время.

Если не считать этого, твой подход - единственный способ, о котором я могу думать.Я фактически удалил бы обе записи и создал бы новую с объединенными данными, в результате чего новый идентификатор клиента вместо повторного использования старого, но это всего лишь личное предпочтение - функционально это то же самое, что и ваш подход.Вы все еще должны помнить, чтобы вернуться и изменить функцию слияния, чтобы отразить новые отношения в поле customer.id.

1 голос
/ 08 марта 2011

Как минимум, чтобы предотвратить любые триггеры при удалении, вызывающие некоторый каскадный эффект, я бы ПЕРВЫМ сделал

обновление SomeTable set CustomerID = CorrectValue где CustomerID = WrongValue

(сделайте это для всех таблиц) ...

ТО Удалить из клиентов, где CustomerID = WrongValue

Что касается дубликатов данных ... Попробуйте выяснить, какой "Уилл Смит, Билл Смит, Уильям Смит", если вам не хватаетопределенная информация ... Некоторые могут быть совершенно легитимными разными людьми.

0 голосов
/ 08 марта 2011

В качестве обновления моего комментария:

use information_schema;
select table_name from columns where column_name = 'customer_id';

Затем переберите получившиеся таблицы и обновите соответственно.

Лично я бы использовал ваше инстинктивное решение, так как это может быть опасно, если есть таблицы, содержащие столбцы customer_id, которые необходимо исключить.

...