如何修复“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
而不必加入 contractdates
。 contractid
和 fieldheadingid
对此至关重要。如果我只有contractdateid
作为外键,这意味着我可以有一个historydate 链接到现有的contractdateid
但包含不存在的contractid
或fieldheadingid
或@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。缺少约束索引”关于创建复合外键的主要内容,如果未能解决你的问题,请参考以下文章