【问题标题】:Working with foreign keys - cannot insert使用外键 - 无法插入
【发布时间】:2011-02-01 17:32:45
【问题描述】:

在 mySQL 数据库中使用外键进行我的第一次试验并尝试进行插入,但由于这个原因而失败:Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

这是否意味着外键限制了每个表上的 INSERTS 以及 DELETES 和/或 UPDATES 是通过外键关系强制执行的?

谢谢!

更新说明:

Products
----------------------------
id    | type
----------------------------
0     | 0
1     | 3

ProductsToCategories
----------------------------
productid | categoryid
----------------------------
0         | 0
1         | 1

产品表具有以下结构

CREATE  TABLE IF NOT EXISTS `alpha`.`products` (
  `id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `type` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 ,    
  PRIMARY KEY (`id`) ,  
  CONSTRAINT `funkyfunky`  
    FOREIGN KEY (`id` )
    REFERENCES `alpha`.`ProductsToCategories` (`productid` )    
    ON DELETE CASCADE,    
    ON UPDATE CASCADE)  

ENGINE = InnoDB;

【问题讨论】:

    标签: mysql database database-design foreign-keys


    【解决方案1】:

    当子表中有外键引用时,您不能从父表中删除行。此外,您不能在外键列中具有无效 id 的子表中插入/更新。

    编辑:“CONSTRAINT funkyfunky FOREIGN KEY (id)”必须在“ProductsToCategories”表中声明,而不是在“Products”表中,因为“ProductsToCategories”引用的是“Products”,而不是与您所做的相反。

    【讨论】:

    • 事情就是这样。我有一个父表和一个子表。两者都是新鲜的空。当我对父表进行插入时,就会发生这种情况。
    • 奇怪。您确定您已正确设置外键吗?我认为您在创建外键时已经颠倒了子表和父表。
    【解决方案2】:

    外键强制在两个表中的行之间建立有效的关系。为了能够在包含外键的表中插入一行,所引用的表中必须有一行包含该键,否则插入将失败。与删除相同,您不能删除引用表中的行,而表中仍有具有外键的行仍然引用它。这可以防止以依赖表中具有数据但在被引用表中没有关联行的行结束,即违反引用完整性。

    【讨论】:

      【解决方案3】:

      您的插入失败,因为您要插入的行中的外键与约束表中的有效键不匹配。例如:

      假设您有这两个表:

      Employees
      ----------------------------
      EmpID | Name
      ----------------------------
      0     | John
      1     | Jane
      
      OfficeAssignments
      ----------------------------
      OfficeID | EmpID
      ----------------------------
      0        | 0
      1        | 1
      

      如果您对OfficeAssignments.EmpID -> Employees.EmpID 有外键约束,并且您尝试执行:

      INSERT INTO OfficeAssignments (OfficeID, EmpID) VALUES (2,2)
      

      语句将失败,因为Employees 表中没有 EmpID 为 2 的条目。

      约束旨在确保您的从属表始终具有与父表相关的有效数据 - 在此示例中,您永远不会有一个办公室被列为分配给系统中不存在的员工, 要么是因为它们从未存在(在本例中),要么是因为它们已被删除(因为约束将阻止删除员工记录,直到首先删除办公室分配记录)。

      编辑: 既然您已经发布了约束,它看起来确实可能是向后设置的。通过将约束放在Products 表的定义中,您将使其成为子表,并将ProductsToCategories 设为父表。您编写的约束可以读作“必须先将产品分配给类别,然后才能创建它”。我怀疑您的意思是相反的:“必须先创建产品,然后才能将其分配给类别。”要获得该结果,您需要将约束放在ProductsToCategories 表上,将外键设置为productid 并引用Products.id

      【讨论】:

      • 但他说父表中的插入(在您的示例员工中)失败。如果外键设置正确,这是不可能失败的。
      • 刚刚注意到(当我开始写这篇文章时,评论还没有出现)。我同意你的回答,听起来约束是向后设置的。
      • 嗨!更新了我的第一篇文章以澄清一些事情!
      【解决方案4】:

      您的产品表略有错误,因为您不需要从中引用任何内容。引用进入“其他”表,并指向主表,例如:

      create table products (
        id int auto_increment,
        type int,
        primary key (id)
      );
      
      create table categories (
        id int auto_increment,
        name varchar(128),
        primary key (id)
      )
      
      create table products_to_categories (
        product_id int references products,
        category_id int references categories
      );
      

      【讨论】:

      • 您好,Einar,感谢您的回答。肯定会对此进行测试,听起来确实可能是一个解决方案!
      • 另一个想法,我希望有一些意见。当产品表使用外键时,删除的产品也将删除与“products_to_categories”表中的类别的连接。这不是使用foreign_keys的最佳方式吗?我的意思是,如果我删除 products_to_categories 中的行,我不想删除该产品?
      • 这本质上是级联删除。删除产品时,“products_to_categories”中的相应条目将被删除。外键当然必须在“products_to_categories”中声明并进行级联删除。您已经添加了 CASCADE 删除。只需将外键移至“products_to_categories”即可。
      • 好东西!非常感谢 Petar 和 Einar!
      猜你喜欢
      • 2018-07-13
      • 2016-06-04
      • 1970-01-01
      • 2014-11-24
      • 2014-08-12
      • 1970-01-01
      • 2018-01-09
      • 2016-05-20
      • 2019-04-13
      相关资源
      最近更新 更多