2009-12-15 3 views
94

При выполнении:Невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не удается

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

It ошибки:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id)) 

Вот мои таблицы:

CREATE TABLE IF NOT EXISTS `advertisers` (
    `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    `password` char(32) NOT NULL, 
    `email` varchar(128) NOT NULL, 
    `address` varchar(255) NOT NULL, 
    `phone` varchar(255) NOT NULL, 
    `fax` varchar(255) NOT NULL, 
    `session_token` char(30) NOT NULL, 
    PRIMARY KEY (`advertiser_id`), 
    UNIQUE KEY `email` (`email`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; 


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES 
(1, 'TEST COMPANY', '', '', '', '', '', ''); 

CREATE TABLE IF NOT EXISTS `jobs` (
    `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `advertiser_id` int(11) unsigned NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `shortdesc` varchar(255) NOT NULL, 
    `longdesc` text NOT NULL, 
    `address` varchar(255) NOT NULL, 
    `time_added` int(11) NOT NULL, 
    `active` tinyint(1) NOT NULL, 
    `moderated` tinyint(1) NOT NULL, 
    PRIMARY KEY (`job_id`), 
    KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; 


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES 
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0); 

ALTER TABLE `advertisers` 
    ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`); 

ответ

65

Как и вы, вы должны удалить строку из таблицы рекламодателей, прежде чем удалять строку в таблице заданий, на которую она ссылается. Это:

ALTER TABLE `advertisers` 
    ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
     REFERENCES `jobs` (`advertiser_id`); 

... на самом деле противоположное тому, что должно быть. Как бы то ни было, это означает, что перед рекламодателями вам придется записывать запись в таблицу заданий. Таким образом, вам необходимо использовать:

ALTER TABLE `jobs` 
    ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
     REFERENCES `advertisers` (`advertiser_id`); 

После исправления отношения внешнего ключа инструкция по удалению будет работать.

+2

В первой строке: разве вы не думаете, что это должно быть «то, что оно ссылается» вместо «, которое ссылается на него»? Или я неправильно понял, как должна работать терминология ссылок? –

+5

@AbrahamPhilip Я думал то же самое. рекламодатели ссылаются на задания. – keyser

24

Под вашим текущий (возможно, ошибочный) дизайн, вы должны удалить строку из таблицы рекламодателей до вы можете удалить строку в таблице заданий, на которую она ссылается.

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

ALTER TABLE `advertisers` 
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`) 
ON DELETE CASCADE; 

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

ALTER TABLE `jobs` 
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`); 

И каскадное удаление не требуется.

+1

Асаф, исправьте меня, если я ошибаюсь, но не будет ли нескольких работ на рекламодателя? –

+0

@ Rashmi: Вы правы –

+0

@ Rashmi Pandit: Я добавил дальнейшее обсуждение к моему ответу, в котором рассматривается этот вопрос. – Asaph

3

Если есть более чем одна работа с тем же advertiser_id, то внешний ключ должен быть:

ALTER TABLE `jobs` 
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`); 

В противном случае (если его наоборот в вашем случае), если вы хотите, чтобы строки в рекламодателю которые будут автоматически удаляются, если строка в задании удаляется добавить «ON DELETE CASCADE» вариант вашего внешнего ключа

ALTER TABLE `advertisers` 
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`); 
ON DELETE CASCASE 

Выезд Foreign Key constraints

5

Я думаю, что ваш внешний ключ обращен назад. Попробуйте:

ALTER TABLE 'jobs' 
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`) 
0

Может быть, вы должны попробовать ON DELETE CASCADE

+26

Слегка добавив каскадное удаление (которое уничтожит данные), не понимая проблемы, это самое худшее, что можно было сделать. –

1

При создании базы данных или создание таблиц

Вы должны добавить эту строку в верхней сценарий создания базы данных или таблицы

SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1; 

Теперь вы хотите удалить записи из таблицы?тогда вы пишете как

SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1; 
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

Удачи вам!

150

Простым способом было бы отключить проверку внешнего ключа; внесите изменения, а затем повторно включите проверку внешнего ключа.

SET FOREIGN_KEY_CHECKS=0; -- to disable them 
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them 
+92

Это не решение проблемы, а скорее грязная работа, которая может быть нежелательной. – madfriend

+11

В моем случае: я просто запустил большой файл SQL, и один из заключительных операторов не удался, поэтому я просто хочу удалить все таблицы, исправить ошибку синтаксиса и повторить, что делает именно то, что я искал. – ekerner

+1

Если вы собираетесь это сделать, почему бы не просто удалить все ограничения? – Sablefoste

0

Вы должны удалить его по заказу Есть зависимость в таблицах

0

, если вам нужно как можно скорее поддержать клиента, и не имеют доступа к

FOREIGN_KEY_CHECKS 

так что целостность данных может быть отключена:

1) удалить внешний ключ

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`; 

2) активировать операцию удаления thruogh SQL или API

3) добавить внешний ключ обратно в схему

ALTER TABLE `advertisers` 
    ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`); 

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

6

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

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE имя_таблицы;

1

Как насчет этой альтернативы я использую: разрешить внешний ключ, чтобы быть NULL, а затем выберите ON DELETE SET NULL.

Лично я предпочитаю использовать как «ON UPDATE CASCADE», а также «ON DELETE SET NULL», чтобы избежать ненужных осложнений, но на вашем установлены, вы можете иной подход. Кроме того, значения NULL'ing внешнего ключа могут в последствии привести к осложнениям, поскольку вы не знаете, что именно там произошло. Таким образом, это изменение должно быть тесно связано с тем, как работает ваш код приложения.

Надеюсь, что это поможет.

2

Я имел эту проблему в Laravel миграции тоже
порядок падения таблиц в пуха() метод имеет значение

Schema::dropIfExists('groups'); 
Schema::dropIfExists('contact'); 

не может работать, но если вы измените порядок, он работает.

Schema::dropIfExists('contact'); 
Schema::dropIfExists('groups'); 
0

Перед удалением задания вы можете создать триггер для удаления ссылочных строк.

DELIMITER $$ 
    CREATE TRIGGER before_jobs_delete 
     BEFORE DELETE ON jobs 
     FOR EACH ROW 
    BEGIN 
     delete from advertisers where advertiser_id=OLD.advertiser_id; 
    END$$ 
    DELIMITER ; 

 Смежные вопросы

  • Нет связанных вопросов^_^