MySQL InnoDB - создать ограничение внешнего ключа CASCADE, когда данные уже существуют, что нарушает их? - PullRequest
1 голос
/ 18 ноября 2010

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

Чтобы исправить это, я решил преобразовать в InnoDB и добавить внешние ключи с CASCADE для обоих обновленийи удаление.Однако, когда я пытаюсь добавить внешний ключ, я получаю такие ошибки (из консоли Navicat 8):

1452 - Cannot add or update a child row: a foreign key constraint fails 
(`database`.`#sql-1358_38d`, CONSTRAINT `#sql-1358_38d_ibfk_1` FOREIGN KEY 
(`manufacturerID`) REFERENCES `manufacturer` (`ID`) ON DE)

Я знаю, почему это происходит, из-за потерянных строк.Есть ли способ, чтобы создание ограничения автоматически очистило эти строки?Потребуются годы, чтобы просмотреть все таблицы и найти потерянные строки.

Это один из запросов, которые я выполняю на всякий случай:

ALTER TABLE part_number ADD CONSTRAINT
FOREIGN KEY(manufacturerID)
REFERENCES manufacturer(ID)
ON DELETE CASCADE
ON UPDATE CASCADE;

Ответы [ 2 ]

2 голосов
/ 18 ноября 2010

написать запрос, который находит потерянные строки, а затем использовать его для удаления. * 1001 например *

SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID) where manufacturer.ID IS NULL

1 голос
/ 22 января 2011

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

Вы можете сделать это двумя способами.

1 Использование не существует ()

DELETE FROM part_number
 WHERE NOT EXISTS (
           select id from manufacturer
            where part_number.manufacturerID = manufacturer.ID
       )

2. Использование временной таблицы (немного некрасиво, но я тоже выложу)

-- create a temporary table
CREATE TEMPORARY TABLE `temp_ids`
(
  `id` INTEGER
);

-- store all id's that need to be deleted
INSERT INTO `temp_ids`
SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID)
WHERE ISNULL(`manufacturer.ID);

-- delete them
DELETE
FROM part_number
WHERE id IN (
  SELECT `id` FROM `temp_ids`
);

-- drop the table
DROP TEMPORARY TABLE `temp_ids`;

См. Мой связанный вопрос: Обработка целостности базы данных

После того как все «мертвые» записи будут удалены, вы сможете добавить ограничение.

Надеюсь, это работает для вас:)

...