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

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

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

我正在使用 mysql 5.6.2

我有一个具有主键item(A,B) 的项目表和具有主键itemsup(A,X,Y) 的项目供应商。我有像 item(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;

最佳答案

为什么会出现错误消息?

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

不幸的是,MySQL 允许引用集是非唯一的或允许 NULL 的唯一集,但随后无法正常工作。来自 the MySQL manual re Using FOREIGN KEY Constraints :

However, the system does not enforce a requirement that the referenced columns be UNIQUE or be declared NOT NULL. The handling of foreign key references to nonunique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only UNIQUE (including PRIMARY) and NOT NULL keys.

特别是from the MySQL manual re InnoDB and FOREIGN KEY Constraints :

If there are several rows in the parent table that have the same referenced key value, InnoDB acts in foreign key checks as if the other parent rows with the same key value do not exist. For example, if you have defined a RESTRICT type constraint, and there is a child row with several parent rows, InnoDB does not permit the deletion of any of those parent rows.

这就是您收到错误的原因。即您有多个 ITEMID 行,在 ITEM 中有相同的行。

调整您的设计

就关系和标准 SQL 概念而言,如果 ITEMID 在 ITEM 中是 UNIQUE,则 ITEMSUP 中只能有 FOREIGN KEY (ITEMID) REFERENCES ITEM (ITEMID)。由于 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')。

如果任何“可能”为真,那么您没有正确描述您的表的约束。除非您确切确认您需要的约束是什么,否则我们无法就您的设计应该是什么提供适当的建议。

关于mysql外键仅引用复合主键的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25665035/

相关文章:

mysql - 如何使用 group-concat mysql 创建 json 格式?

Django admin - 没有外键或多对多关系的自动完成(_field)

mysql - mysql中删除级联和更新级联的区别

hibernate - 我应该如何覆盖具有复合主键的实体中的 equals/hashCode?

mysql - 查询导致另一表中的一行的多行

php - 即使使用 LIMITS,Mysql 查询也需要很长时间

database - 将外键作为主键可以吗?

sql - 如何将复合主键插入到另一个表中?

entity-framework - 具有复合键的自定义 EF Core AddOrUpdate

mysql - 从另一个表中日期时间为今天的表中选择计数