【问题标题】:ERROR 1451: 1451: Cannot delete or update a parent row: a foreign key constraint fails错误 1451:1451:无法删除或更新父行:外键约束失败
【发布时间】:2014-11-02 06:05:43
【问题描述】:

我一直在寻找这个错误,偶然发现了几个相同性质的问题, 但据我了解,他们似乎关心更新问题。我的源于删除条目。

我的桌子是这样制成的:

CREATE TABLE `product` (
  `product_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT COMMENT
 'represents unique identifier for every existing products',
  `code` varchar(20) NOT NULL,
  `name` varchar(45) NOT NULL COMMENT 'description',
  `price` decimal(11,4) NOT NULL,
  `short_name` varchar(10) NOT NULL COMMENT 
'name that can be used quickly to referenc or immediately know what is the product',
  `count` bigint(19) unsigned NOT NULL DEFAULT '0',
  `product_type_id` smallint(5) unsigned NOT NULL DEFAULT '0',
  `is_active` bit(1) NOT NULL DEFAULT b'0',
  PRIMARY KEY (`product_id`),
  KEY `product_product_typeFK_idx` (`product_type_id`),
  CONSTRAINT `product_product_typeFK` FOREIGN KEY (`product_type_id`) REFERENCES
 `product_type` (`product_type_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
  ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

然后它还有一些附带的TRIGGER 插入一些数据:

USE `RFVPOS`;
DELIMITER $$
CREATE TRIGGER `Product_BDEL` BEFORE DELETE ON `product` FOR EACH ROW

BEGIN
    INSERT INTO `product_audit`
    (product_id,
    code, 
    name, 
    short_name, 
    price,
    count,
    delete_user,
    delete_date
    )

    values
    (OLD.product_id,
    OLD.code,
    OLD.name,
    OLD.short_name,
    OLD.price,
    OLD.count,
    CURRENT_USER(),
    NOW()
    );
END

这里也是'product_audit'的结构:

CREATE TABLE `product_audit` (
  `product_audit_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` mediumint(8) unsigned NOT NULL,
  `code` varchar(20) NOT NULL,
  `name` varchar(45) NOT NULL,
  `price` decimal(11,4) NOT NULL,
  `short_name` varchar(10) NOT NULL,
  `count` bigint(19) unsigned NOT NULL,
  `delete_user` varchar(45) NOT NULL,
  `delete_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`product_audit_id`),
  KEY `product_audit_productFK_idx` (`product_id`),
  CONSTRAINT `product_audit_productFK` FOREIGN KEY (`product_id`) REFERENCES `product` (`product_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

然后它会闪烁这个错误:

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

现在,让我感到困惑的是,没有其他表条目一直在使用我在“产品”表上删除的条目。这次删除应该很顺利。

所以,我尝试在“产品”表和 BLAM 上删除我的 TRIGGER,删除成功。
这意味着错误出在我的触发器上,您能帮我指出确切的位置(如果不在触发器上)以及为什么会发生错误。

【问题讨论】:

    标签: mysql database rdbms


    【解决方案1】:

    在删除产品之前,您的触发器将插入product_audit。如果product_audit 中的product_id 列是product 的外键,则不能再从product 中删除该行,因为它是product_audit 中新创建行的父行。

    尝试从product_audit中移除外键约束。

    由于您没有显示product_audit 的表定义,因此以上是在这方面的猜测。 (在撰写本文时,就是这样。但我的猜测是正确的!)

    【讨论】:

    • 这个答案说得很清楚。顺便说一句,是否建议在 product_audit 中设置约束?我的意思是,有任何表可以捕获已删除的条目吗?
    • 您尝试实现的是“软删除”或类似的东西。所以你想从数据库中删除你的条目,但不是完全 - 你想备份它们,对吗?在这种情况下,我不会将这些条目移动到另一个表中,但我会在您的product 表中创建另一个名为deleted 的列。默认值为 0 / 假。每当您想从product 中删除一行时,只需将deleted 设置为1 / true。每当您从 product 中选择时,将 WHERE deleted=0 添加到您的查询中。您还可以使用 WHERE 语句为您的 product 表创建一个视图。
    • 是的。为什么我想把它放在另一张桌子上是为了避免桌子变大,影响性能?我不太确定我说了什么..
    • 如果您担心您的表会增长太多,您也可以将已删除的列更改为时间戳并允许NULL 值。 NULL 表示此列尚未删除。删除时,将列设置为NOW()。然后,您可以每隔一段时间从您的表中完全DELETE 行,这些行已在某个时间前(即一个多月前,或类似的东西)被删除。您仍然可以恢复最近删除的行,但您的表不会无限增长。
    • 我建议您创建另一个问题,在其中说明您的问题以进行软删除。提及不同的方法,您已经考虑过并说明您在每种方法中看到的缺点,并就如何最好地实现您的目标(明确指定它们)寻求建议!
    【解决方案2】:

    您在product 表中尝试delete 的条目是其他表的parent。这意味着,如果您尝试从 product_id=1 所在的 product 表中删除一个条目,您必须确保首先删除所有引用该条目的条目。

    假设您有一个名为user的表

    +--------+-------+--------+
    | UserID | Name  | Gender |
    +--------+-------+--------+
    | 1      | Jason | Male   |
    +--------+-------+--------+
    | 2      | Sara  | Female |
    +--------+-------+--------+
    | 3      | John  | Male   |
    +--------+-------+--------+
    

    你有一个表 user_address 引用 user 表,user_id 是外键。

    +-----------+-----------+--------+
    | AddressID | Address   | UserID |
    +-----------+-----------+--------+
    | 1         | Address A | 1      |
    +-----------+-----------+--------+
    | 2         | Address B | 1      |
    +-----------+-----------+--------+
    | 3         | Address C | 2      |
    +-----------+-----------+--------+
    

    现在,如果您想在 user 上运行删除查询,如下所示:

    delete from user where userID=1;
    

    您必须确保删除它的所有子项(依赖项),在此游戏中为 Address AAddress B

    【讨论】:

    • “现在,让我感到困惑的是,没有其他表条目一直在使用我在 'product' 表上删除的条目。这次删除应该很顺利。” - 正如我上面所说。和你说的一样吗?你是什​​么意思的其他表的父母?你的意思是,是某个其他表的外键吗?
    【解决方案3】:

    您可以通过运行以下查询来检查product_id 是否在任何其他表中用作FOREIGN KEY

    SELECT    constraint_name,    table_name
     FROM    information_schema.table_constraints 
     WHERE  constraint_type = 'FOREIGN KEY'
      AND table_schema = DATABASE()
      AND constraint_name LIKE '%product_id%'
    ORDER BY    constraint_name;`
    

    【讨论】:

      猜你喜欢
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 2022-09-23
      • 2019-10-24
      • 2020-08-10
      • 2021-06-14
      相关资源
      最近更新 更多