mysql外键仅引用复合主键的一部分

时间:2014-09-04 12:04:37

标签: mysql foreign-keys composite-primary-key sql-delete

当外键仅引用复合主键的一部分时,如何从父表中删除

我正在使用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;

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')。

如果任何“可能”为真,那么您没有正确描述表格上的约束。除非您确切知道所需的限制是什么,否则我们无法正确建议您的设计应该是什么。