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

问题描述 投票:2回答:1

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

我使用mysql 5.6.2。

我有一个项目表,其中有主键 项(A,B) 和项目供应商,它们的主要关键是 itemsup(A,X,Y)......我有这样的参考资料 item(A) = itemsup(A) 当我从 item(parent) 表中删除时,我得到了错误信息。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#!9fb9611

我已经找到了一个解决方案,但不确定它是对还是错。

SET FOREIGN_KEY_CHECKS = 0;
DELETE FROM ITEM WHERE ITEMID =1 AND MCA ='A';
SET FOREIGN_KEY_CHECKS = 1;
mysql foreign-keys composite-primary-key sql-delete
1个回答
1
投票

为什么会出现错误信息?

在标准SQL中,引用的列集必须声明为UNIQUE或PRIMARY KEY。MySQL可以正常引用UNIQUE NOT NULL或PRIMARY KEY。

不幸的是,MySQL允许引用的列集是非UNIQUE或UNIQUE,并允许NULLs,但却不能正常工作。从 MySQL手册中关于使用 FOREIGN KEY 约束的内容。:

然而,系统并没有强制要求被引用的列是UNIQUE的,或被宣布为NOT NULL。对于UPDATE或DELETE CASCADE等操作,没有很好地定义如何处理外键引用非唯一键或包含NULL值的键。建议你使用只引用UNIQUE(包括PRIMARY)和NOT NULL键的外键。

特别是 来自MySQL手册中关于InnoDB和 FOREIGN KEY约束的内容。:

如果在父表中有几条具有相同引用键值的行,InnoDB在外键检查中的行为就像具有相同键值的其他父行不存在一样。例如,如果你定义了一个restrict类型的约束,并且有一个子行有几条父行,InnoDB不允许删除任何一条父行。

这就是为什么你会得到这个错误。即你有多条ITEMID行与ITEM中的同一行。

调整你的设计

用关系和标准SQL的概念来说,只有当ITEMID在ITEM中是UNIQUE时,才能在ITEMSUP中出现FOREIGN KEY(ITEMID)REFERENCES ITEM(ITEMID)。由于ITEMID不是你的意思,在ITEM中是唯一的,所以你不可能对它要FOREIGN KEY。(非正式地讲,ITEMID不是ITEM的 "key",所以它不可能是ITEMSUP中的外来 "key")。

如果只想让每个ITEMSUP的ITEMID都是ITEMITID的值,就把ITEMID作为一个新表的PRIMARY KEY,并从ITEMID和ITEMSUP中为它设置一个FOREIGN KEY(而不是当前ITEMSUP的外键)。

改进你的设计

也许'X'是一种 "null",表示没有MCA,不一定要有匹配的MCS,也可能ITEMSUP ITEMID的MCA在非'X'或'X'时必须与ITEM的MCA匹配。也可能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')。

如果任何 "也许 "是真的,那么你没有正确描述你的表的约束。除非你确认你所需要的约束条件到底是什么,否则我们无法正确建议你的设计应该是什么。

© www.soinside.com 2019 - 2024. All rights reserved.