如何修复“MySQL 错误:1822。缺少约束索引”关于创建复合外键

Posted

技术标签:

【中文标题】如何修复“MySQL 错误:1822。缺少约束索引”关于创建复合外键【英文标题】:How to fix 'MySQL Error: 1822. Missing index for contraint' On creating a composite foreign key 【发布时间】:2019-12-02 03:56:03 【问题描述】:

我正在尝试使用复合外键创建表,但不断遇到错误 Error Code: 1822. Failed to add the foreign key constraint. Missing index for constraint 'fk_contractdateshistoric_contractdates_multiple' in the referenced table 'contractdates'

我正在使用mysql v8.0.16

我检查了列类型是否不同,但我不确定还有什么问题。

这里是构成问题的表,所有表都制作得很愉快,但最后一个包含复合键的表会导致问题。

CREATE TABLE `contracts` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` varchar(100) DEFAULT NULL,
  `CreationDate` datetime DEFAULT NULL,
  `CreatedBy` varchar(30) DEFAULT NULL,
  `CompletionDate` date DEFAULT NULL,
  `Comments` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`ID`)
);

CREATE TABLE `fieldheading` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `fieldTypeID` int(11) DEFAULT NULL,
  `fieldCode` int(11) DEFAULT NULL,
  `fieldHeading` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`ID`)
);

CREATE TABLE `contractdates` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
  `DateValue` datetime DEFAULT NULL,
  `ContractID` int(11) NOT NULL,
  `FieldHeadingID` int(11) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `uq_contractdates_contractID_FieldHeading_ID` (`ContractID`,`FieldHeadingID`),
  KEY `fk_contractdates_contracts_id_idx` (`ContractID`),
  KEY `fk_contractdates_fieldheading_id_idx` (`FieldHeadingID`),
  CONSTRAINT `fk_contractdates_fieldheading_id` FOREIGN KEY (`FieldHeadingID`) REFERENCES `fieldheading` (`id`),
  CONSTRAINT `fk_contractdates_contracts_id` FOREIGN KEY (`ContractID`) REFERENCES `contracts` (`id`)
) COMMENT='Table to hold the dates for a contract, one row is one date for a specific contract';

CREATE TABLE `contractdateshistoric` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `ContractID` int(11) NOT NULL,
  `ContractDateCurrentID` int(11) NOT NULL,
  `FieldHeadingID` int(11) NOT NULL,
  `ChangedByID` int(11) NOT NULL,
  `DateValue` datetime NOT NULL,
  `TimeStampChanged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`ID`),
  KEY `fk_contractdateshistoric_contractdates_mutiple_idx` (`ContractID`, `FieldHeadingID`, `ContractDateCurrentID`),
  CONSTRAINT `fk_contractdateshistoric_contractdates_multiple` FOREIGN KEY (`ContractID`, `FieldHeadingID`, `ContractDateCurrentID`) REFERENCES `contractdates` (`contractid`, `fieldheadingid`, `id`)
) COMMENT='Audit trail of the dates';

【问题讨论】:

【参考方案1】:

由于您在表 contractdates 中使用复合 FK,请尝试添加复合索引

  KEY `fk_contractdates_mutiple_idx` (`ContractID`,`FieldHeadingID`,`ID`)

整个创建语句

CREATE TABLE `contractdates` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
  `DateValue` datetime DEFAULT NULL,
  `ContractID` int(11) NOT NULL,
  `FieldHeadingID` int(11) NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `fk_contractdates_contracts_id_idx` (`ContractID`),
  KEY `fk_contractdates_fieldheading_id_idx` (`FieldHeadingID`),
  KEY `fk_contractdates_mutiple_idx` (`ContractID`,`FieldHeadingID`,`ID`),
  CONSTRAINT `fk_contractdates_fieldheading_id` FOREIGN KEY (`FieldHeadingID`) REFERENCES `fieldheading` (`id`),
  CONSTRAINT `fk_contractdates_contracts_id` FOREIGN KEY (`ContractID`) REFERENCES `contracts` (`id`)
) COMMENT='Table to hold the dates for a contract, one row is one date for a specific contract';

【讨论】:

【参考方案2】:

它试图告诉你“你没有在contractdates上创建一个必要的唯一索引,它涵盖了列(contractid,fieldheadingid,id),所以我不能在contractdatehistoric上创建一个引用这组的外键确定单个父行时的列"

我不确定你为什么要创建一个引用 3 列的 fk,而contractdates 的 pk 只是 ID 列。

如果contractdatehistoric 记录引用单个contractdates 记录作为其父项,则历史记录应该有一个contractdateid 列,该列引用contractdates.id - 不需要多个列。复制您用于将合同日期与其父合同相关联的模式,您会没事的

【讨论】:

我创建了一个引用 3 列的 fk,因为我希望能够加入 contractdateshistoric 而不必加入 contractdatescontractidfieldheadingid 对此至关重要。如果我只有contractdateid 作为外键,这意味着我可以有一个historydate 链接到现有的contractdateid 但包含不存在的contractidfieldheadingid 或@987654329 中不存在的组合@。也许我可以省略contractdatesid,但这仍然会造成多外键问题。如果我错了,请纠正我。 另外,contractdates 中的 fieldheadingid 和 contractid 的组合应该是 UNIQUE 而不是 contractdateshistoric,我会更新问题以反映这一点。 Erm.. 当然contractdateshistoric,只是一个自动维护的历史表(由触发器?)不需要这个 FK,因为它只会包含具有有效 contractid 的值/字段标题ID。您不需要对历史表进行 FK,因为它仅从已经 FK 的表中获取其数据。您不能将 ContractDates 表更改为具有不存在的 FieldHeadingId,因此历史表中也不能包含错误数据。如果您想加入与 FK 无关的历史表。即使没有 FK,也可以加入表 但话虽如此,contractdateshistoric 不应该有一个对 contractdates 的 FK,因为它不是 contractdates 的子表,它是一个兄弟表,因此它的条目具有相同的规则,它应该有如果你真的坚持,FKs 合同和现场指挥(但这不是必需的,可能会在某个时候绊倒你 您对触发器部分的看法是正确的,我想我只是想多了,因为这是我最初设计的一部分。【参考方案3】:

我已尝试为列单独创建键,请查找更新后的查询:

CREATE TABLE `contractdateshistoric` (
    `ID` INT(11) NOT NULL AUTO_INCREMENT,
    `ContractID` INT(11) NOT NULL,
    `ContractDateCurrentID` INT(11) NOT NULL,
    `FieldHeadingID` INT(11) NOT NULL,
    `ChangedByID` INT(11) NOT NULL,
    `DateValue` DATETIME NOT NULL,
    `TimeStampChanged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`ID`),
    KEY `fk_contractdateshistoric_contractdates_mutiple_idx` (`ContractID`),
    KEY `fk_contractdateshistoric_contractdates_mutiple_idx1` (`FieldHeadingID`),
    KEY `fk_contractdateshistoric_contractdates_mutiple_idx2` (`ContractDateCurrentID`),
    CONSTRAINT `fk_contractdateshistoric_contractdates_multiple` FOREIGN KEY (`ContractID`)
    REFERENCES `contractdates` (`contractid`),
    CONSTRAINT `fk_contractdateshistoric_contractdates_multiple1` FOREIGN KEY (`FieldHeadingID`)
    REFERENCES `contractdates` (`fieldheadingid`),
    CONSTRAINT `fk_contractdateshistoric_contractdates_multiple2` FOREIGN KEY (`ContractDateCurrentID`)
    REFERENCES `contractdates` (`id`)
);

效果很好。

【讨论】:

OP 说 复合索引 不起作用。

以上是关于如何修复“MySQL 错误:1822。缺少约束索引”关于创建复合外键的主要内容,如果未能解决你的问题,请参考以下文章

如何修复drv?

如何修复漏洞

如何修复WMI

PHP网站漏洞怎么修复 如何修补网站程序代码漏洞

如何修复这些漏洞? (npm audit fix 无法修复这些漏洞)

如何修复AppScan漏洞