【问题标题】:Mysql composite key out of a foreign composite keyMysql组合键出外组合键
【发布时间】:2026-01-14 23:30:01
【问题描述】:

我试图在 Mysql WorkBench 中的两个表之间建立多对多关系,而这两个表中的一个具有复合主键(部分来自 2 个外键)。当我尝试生成 SQL 时,出现此错误:

错误:错误 1215:无法添加外键约束

SQL 代码:

    -- -----------------------------------------------------
    -- Table `A_D_schema`.`Resources_has_OwnerGroups`
    -- -----------------------------------------------------
    CREATE TABLE IF NOT EXISTS `A_D_schema`.`Resources_has_OwnerGroups` (
      `Resources_id` INT NOT NULL,
      `OwnerGroups_id` INT NOT NULL,
      `OwnerGroups_Instances_has_Customers_Instances_idInstances` INT NOT NULL,
      `OwnerGroups_Instances_has_Customers_Customers_idCustomers` INT NOT NULL,
      PRIMARY KEY (`Resources_id`, `OwnerGroups_id`, `OwnerGroups_Instances_has_Customers_Instances_idInstances`, `OwnerGroups_Instances_has_Customers_Customers_idCustomers`),
      INDEX `fk_Resources_has_OwnerGroups_OwnerGroups1_idx` (`OwnerGroups_id` ASC, `OwnerGroups_Instances_has_Customers_Instances_idInstances` ASC, `OwnerGroups_Instances_has_Customers_Customers_idCustomers` ASC),
      INDEX `fk_Resources_has_OwnerGroups_Resources1_idx` (`Resources_id` ASC),
      CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
        FOREIGN KEY (`Resources_id`)
        REFERENCES `A_D_schema`.`Resources` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
      CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
        FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
        REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB

SHOW ENGINE INNODB STATUS我可以看到这条消息:

Cannot resolve column name close to:
)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
    FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
    REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

SHOW CREATE TABLE ResourcesSHOW CREATE TABLE OwnerGroups

CREATE TABLE `Resources` (
  `idResources` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(45) DEFAULT NULL,
  `role` int(11) DEFAULT NULL COMMENT 'role : 1 disptcher \n0 admin',
  PRIMARY KEY (`idResources`),
  UNIQUE KEY `idresources_UNIQUE` (`idResources`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `OwnerGroups` (
  `idOwnerGroups` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `group` int(11) DEFAULT NULL,
  PRIMARY KEY (`idOwnerGroups`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

【问题讨论】:

    标签: mysql many-to-many foreign-key-relationship composite-primary-key composite-key


    【解决方案1】:
      CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
        FOREIGN KEY (`Resources_id`)
        REFERENCES `A_D_schema`.`Resources` (`id`)
    

    您的资源表没有id 列。它的主键是idResources

      CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
        FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
        REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
    

    您的 OwnerGroups 表没有 id 列。它的主键是idOwnerGroups。它根本没有您引用的其他两列。


    一般来说,当你声明一个外键时,首先你命名子表中的列:

    CREATE TABLE Child (
      childCol1 INT,
      childCol2 INT,
    ...
    FOREIGN KEY (childCol1, childCol2) ...
    

    然后你引用父表中的列:

    ... REFERENCES Parent (parentCol1, parentCol2)
    );
    

    您必须使用列名,因为它们存在于父表中。

    您在父表中引用的列必须一起是该表的 PRIMARY KEY 或 UNIQUE KEY。换句话说,鉴于上面的示例,它不适用于此 Parent 表:

    CREATE TABLE Parent (
      parentCol1 INT,
      parentCol2 INT,
      PRIMARY KEY (parentCol1)
    );
    

    因为 PRIMARY KEY 不包括 parentCol2。


    在你的情况下,以下应该有效:

    CREATE TABLE IF NOT EXISTS `A_D_schema`.`Resources_has_OwnerGroups` (
      `Resources_id` INT NOT NULL,
      `OwnerGroups_id` INT NOT NULL,
      `OwnerGroups_Instances_has_Customers_Instances_idInstances` INT NOT NULL,
      `OwnerGroups_Instances_has_Customers_Customers_idCustomers` INT NOT NULL,
      PRIMARY KEY (`Resources_id`, `OwnerGroups_id`, `OwnerGroups_Instances_has_Customers_Instances_idInstances`, `OwnerGroups_Instances_has_Customers_Customers_idCustomers`),
      CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
        FOREIGN KEY (`Resources_id`)
        REFERENCES `A_D_schema`.`Resources` (`idResources`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
      CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
        FOREIGN KEY (`OwnerGroups_id`)
        REFERENCES `A_D_schema`.`OwnerGroups` (`idOwnerGroups`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION
    ) ENGINE = InnoDB
    

    我删除了几个冗余的 INDEX 定义。您不需要索引 PRIMARY KEY,它已经是表的聚集索引。您不需要为在外键声明中使用的列建立索引,如果需要,MySQL 会自动为该列建立索引(尽管如果该列已经存在索引,则 FK 约束将使用该索引)。

    我不确定我是否理解您的另外两列 OwnerGroups_Instances_has_Customers_Instances_idInstancesOwnerGroups_Instances_has_Customers_Customers_idCustomers 的用途。通常在多对多表中,您只需要足够的列来引用各个父表的主键。


    你的评论:

    您应该不时尝试刷新架构视图。在“SCHEMAS”的右侧有一个带有一对弯曲箭头的按钮。

    【讨论】:

    • 好的,谢谢你的评论。我注意到它来自世界银行。我有名为 idResources 的 ID,将它们重命名为 id。但它仍然存在于脚本中。在左侧面板上,我什至可以看到名称重复的表,因为我删除了这些表......我删除了 Resources_has_OwnerGroups 并且它仍然存在于脚本中。 WB有这么麻烦吗?
    • 如果我理解正确你的评论,复合键的最佳实践是什么?假设表 Resources_has_OwnerGroups: 创建一个新的键 Resources_has_OwnerGroups_id 由 fk_Resources_id 和 fk_OwnerGroups_id 组成?
    • PRIMARY KEY (Resources_id, OwnerGroups_id) 是最佳实践。如果您包含更多列,则它允许相对于前两列存在重复项。主键的成员是 columns,而不是 FK 约束。