当外键仅引用复合主键的一部分时,如何从父表中删除
我正在使用mysql 5.6.2
我有一个项目表,其中主键项目(A,B)和项目供应商具有主键项目(A,X,Y)。我提供了像项目(A)= itemsup(A)这样的参考
当我从项目(父)表中删除时,我收到错误: 1451 - 无法删除或更新父行:外键约束失败
我的表格结构如下。
CREATE TABLE IF NOT EXISTS ITEM ( /* parent */
ITEMID INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ITEM ID',
MCA ENUM('A','C','M','X') NOT NULL ,
ITEMNAME VARCHAR(100) NOT NULL COMMENT 'NAME OF ITEM',
PRIMARY KEY (ITEMID, MCA)
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS ITEMSUP ( /* child */
ITEMID INT UNSIGNED NOT NULL,
SUPID INT UNSIGNED NOT NULL,
MCA ENUM('A','C','M','X') NOT NULL ,
PRIMARY KEY (ITEMID, SUPID, MCA),
CONSTRAINT FK_ITEMSUP_ITEM1
FOREIGN KEY (ITEMID)
REFERENCES ITEM (ITEMID)
ON DELETE NO ACTION
ON UPDATE CASCADE
)
ENGINE = InnoDB;
INSERT INTO ITEM (ITEMID, MCA, ITEMNAME) VALUES ( 1,'A', 'ONE A');
INSERT INTO ITEM (ITEMID, MCA, ITEMNAME) VALUES ( 1,'M', 'ONE M');
INSERT INTO ITEMSUP(ITEMID, SUPID, MCA) VALUES(1,1,'X');
/* below is not working */
DELETE FROM ITEM WHERE ITEMID = 1 AND MCA ='A';
http://sqlfiddle.com/#!9/fb961/1
我找到了一个解决方案,但不确定是对还是错。
SET FOREIGN_KEY_CHECKS = 0;
DELETE FROM ITEM WHERE ITEMID =1 AND MCA ='A';
SET FOREIGN_KEY_CHECKS = 1;
答案 0 :(得分:1)
为何出现错误消息?
在标准SQL中,引用的列集必须声明为UNIQUE NON NULL或PRIMARY KEY。
不幸的是,MySQL允许引用的集不是唯一的非空。来自the MySQL manual re Using FOREIGN KEY Constraints:
但是,系统不强制执行引用的要求 列为UNIQUE或声明为NOT NULL。外键的处理 对非唯一键或包含NULL值的键的引用不是 为UPDATE或DELETE CASCADE等操作定义良好。你是 建议使用仅引用UNIQUE的外键(包括 PRIMARY)和NOT NULL键。
特别是from the MySQL manual re InnoDB and FOREIGN KEY Constraints:
如果父表中有多个行具有相同的行 引用键值,InnoDB就像在外键中一样 具有相同键值的其他父行不存在。例如, 如果您已经定义了RESTRICT类型约束,并且有一个子级 具有多个父行的行,InnoDB不允许删除 任何这些父行。
这就是您收到错误的原因。即您在ITEM中有多个ITEMID行和相同的行。
调整您的设计
就关系和标准SQL概念而言,如果ITEMID是唯一的,那么在ITEMSUP中只能有FOREIGN KEY(ITEMID)REFERENCES ITEM(ITEMID)。在ITEM中不为空。由于ITEMID并不意味着您在ITEM中是唯一的,因此您不可能想要一个FOREIGN KEY。 (非正式地,ITEMID不是ITEM的“关键”,所以它不能成为ITEMSUP中的外国“关键”。)
要让每个ITEMSUP ITEMID都是ITEM ITEMID的值,请创建一个新表的ITEMID PRIMARY KEY,并从ITEMID和ITEMSUP(而不是当前的ITEMSUP外键)中获取FOREIGN KEY。
改善设计
也许'X'是一种“null”,表示没有MCA,并且不必是匹配的MCS。和/或可能是ITEMSUP ITEMID的MCA必须在非'X'和/或'X'时匹配其ITEM MCA。也许您只想在ITEM中每个ITEMID使用一个MCA,在这种情况下,将ITEM更改为具有ITEMID PRIMARY KEY和MCA NOT NULL UNIQUE。也许ITEM可以有多个ITEMID-MCA对,但ITEMSUP只能有那些,在这种情况下有一个不同的ITEMSUP外键:
FOREIGN KEY (ITEMID,MCA) REFERENCES ITEM (ITEMID,MCA)
但是这会被你的SQLFiddle违反:
INSERT INTO ITEMSUP(ITEMID, SUPID, MCA) VALUES(1,1,'X');
因为ITEM中没有相应的子行(1,'X')。
如果任何“可能”为真,那么您没有正确描述表格上的约束。除非您确切知道所需的限制是什么,否则我们无法正确建议您的设计应该是什么。