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


170

При выполнении:

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

Это ошибки:

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

Ответы:


108

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

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

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


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

6
@AbrahamPhilip Я думал о том же. рекламодатели ссылаются на вакансии.
кейсер

270

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

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

171
Это не решение проблемы, а грязный обходной путь, который может быть нежелателен.
безумный друг

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

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

1
Это полезно, когда вы делаете что-то вроде:REPLACE INTO tab_with_constraint ...
Maciek Łoziński

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

38

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

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

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

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


18

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

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE table_name;


13

Я попробовал решение, упомянутое @Alino Manzi, но оно не сработало для меня в таблицах, связанных с WordPress, используя wpdb.

Затем я изменил код, как показано ниже, и он работал

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key

6

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

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

5

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

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

Проверьте ограничения внешнего ключа



2

Когда вы создаете базу данных или создаете таблицы

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

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

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

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

Удачи!


2

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

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

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


2

Я имел эту проблему в миграции Laravel слишком
ПОРЯДКОВЫЙ капельные таблиц в пуха () метод имеет значения

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

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

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

1

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

FOREIGN_KEY_CHECKS

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

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

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

2) активировать операцию удаления через sql или api

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

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

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


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 ;

0

Основная проблема с этим erorr Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsзаключается в том, что он не сообщает , в какой таблице содержится ошибка FK, поэтому конфликт трудно разрешить.

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

  1. Используйте MySQL верстак
  2. Нажмите на базу данных -> Обратный инжиниринг
  3. Выберите правильный connection
  4. Далее до конца, не забудьте выбрать databaseи tablesчто нужно изучить
  5. Теперь у вас есть диаграмма ER, вы можете увидеть, какая таблица имеет конфликт FK

0

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


0

Это также случилось со мной, и из-за зависимости и ссылки из других таблиц я не смог удалить запись. Я добавил столбец удаления (типа boolean) в таблицу. Значение в этом поле показывает, помечен ли элемент для удаления или нет. Если помечено для удаления, не извлекать / использовать; в противном случае, используйте его.


-1

Может быть, вам стоит попробовать УДАЛИТЬ КАСКАД


34
Слепое добавление каскадного удаления (которое уничтожит данные) без понимания проблемы - это самое худшее, что можно сделать.
Том Х
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.