无法删除或更新父行:外键约束失败


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

Answers:


108

照原样,必须先删除Advertisers表中的行,然后才能删除它引用的Jobs表中的行。这个:

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

纠正外键关系后,您的delete语句将起作用。


3
在第一行中:您不认为应该是“引用”而不是“引用”吗?还是我误解了参考术语应该如何工作?
亚伯拉罕·菲利普

6
@AbrahamPhilip我在想同样的事情。广告商参考职位。
按键

270

简单的方法是禁用外键检查。进行更改,然后重新启用外键检查。

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

171
这不是解决问题的方法,而是可能不需要的解决方法。
madfriend 2014年

20
就我而言:我只是运行了一个大型SQL文件,而最后一条语句失败了,所以我只想删除所有表,修复语法错误,然后重新运行,这正是我想要的。
ekerner 2014年

1
如果要执行此操作,为什么不删除所有约束呢?
Sablefoste

1
在执行以下操作时很有用:REPLACE INTO tab_with_constraint ...
MaciekŁoziński16年

5
支持此答案的唯一原因是,如果您只是希望您的代码在不理解您正在编写的代码的情况下停止对您大吼大叫并深入研究意大利面条。首先具有外键的原因是为了强制引用完整性。如果需要禁用它们以关闭代码,则可能需要重新考虑外键,而不是禁用它们。
cytinus

38

在您当前的设计(可能有缺陷)下,必须先删除Advertiser表中的行,然后才能删除其引用的Jobs表中的行。

或者,您可以设置外键,以使父表中的删除导致子表中的行被自动删除。这称为级联删除。看起来像这样:

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

并不需要级联删除。



13

我尝试了@Alino Manzi提到的解决方案,但是在使用wpdb的WordPress相关表上,它对我不起作用。

然后我修改了代码如下

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

如果有一个以上的工作具有相同的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 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

这种错误的主要问题Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails是它不会让您知道哪个表包含 FK故障,因此很难解决冲突。

如果您使用MySQL或类似的软件,我发现您可以为数据库创建ER图,那么您可以查看并安全地删除任何引发错误的冲突。

  1. 使用MySQL工作台
  2. 单击数据库->逆向工程
  3. 选择一个正确的 connection
  4. 接下来直到最后,记得选择databasetables需要检查
  5. 现在您有了ER图,可以看到哪个表存在FK冲突

0

基本上,导致此类错误的原因是,您最终将尝试删除具有主键(根表)且该主键在子表中用作外键的tupple。在这种情况下,为了删除父表数据,您必须删除子表数据(使用外键)。谢谢


0

我也发生了这种情况,并且由于其他表的依赖性和引用,我无法删除该条目。我所做的是在表中添加了一个delete列(布尔类型)。该字段中的值显示该项目是否标记为删除。如果标记为删除,则不要获取/使用;否则,请使用它。


-1

也许您应该尝试DELETE CASCADE


34
在不了解问题的情况下盲目添加级联删除(这将破坏数据)仅是人们可能做的最坏的事情。
汤姆H
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.