2010-11-18 1 views
1

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

Чтобы исправить это, я решил конвертировать в 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

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

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

+0

Ну это по сути то, что я начал делать, но это займет некоторое время, просто интересно, если есть возможность не придется делать это вручную. – Gnuffo1

1

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

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

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`; 

Смотрите мой родственный вопрос: Handling database integrity

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

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