多列外键:将单列设置为Null" ON DELETE"而不是全部

时间:2015-11-16 12:21:14

标签: mysql sql foreign-keys innodb mariadb

常规:给定多个列的外键,其中一些可能为NULL 默认情况下(MATCH SIMPLE)只要多列外键的至少一列为NULL,MySQL / MariaDB InnoDB就不会检查外键。

要求:如果从父对象中删除一行,则应将相应子项的一列设置为NULL,而不是外键中的两列。

示例/说明:学生可能会被列为讲座,也可能是其中一个讲座组。如果讲座被删除,则应删除所有学生列表(Works)及其所有组(Works)。如果只删除了一个组,那么学生仍应列入讲座,但不应再将他们分配到一个组(问题)。

示例/ SQL :以下SQL说明了此示例,但最后一个语句不起作用,因为最后一个FOREIGN KEY要求讲义和groupId都是NULLable,但同时使两者都为NULL将意味着删除一个组也会将lectureId设置为NULL。

CREATE TABLE lectures (
  lectureId INT NOT NULL,
  title VARCHAR(10) NOT NULL,
  PRIMARY KEY (lectureId)
 );

CREATE TABLE groups (
  lectureId INT NOT NULL,
  groupNo INT NOT NULL,
  title VARCHAR(10) NOT NULL,
  PRIMARY KEY (lectureId,groupNo),
  FOREIGN KEY (lectureId) REFERENCES lectures (lectureId)
    ON UPDATE CASCADE ON DELETE CASCADE
 );

CREATE TABLE studentListed (
  studentId INT NOT NULL,
  lectureId INT NOT NULL,
  groupNo INT NULL,
  PRIMARY KEY (studentId,lectureId),
  FOREIGN KEY (lectureId) REFERENCES lectures (lectureId)
    ON UPDATE CASCADE ON DELETE CASCADE,
  FOREIGN KEY (lectureId,groupNo) REFERENCES groups (lectureId,groupNo)
    ON UPDATE CASCADE ON DELETE SET NULL
 );

1 个答案:

答案 0 :(得分:0)

经过一些研究后,似乎无法使用外键实现特定要求。

最佳解决方案似乎是混合使用外键触发器

通过以下语句可以解决给定示例的问题:

CREATE TABLE lectures (
  lectureId INT NOT NULL,
  title VARCHAR(10) NOT NULL,
  PRIMARY KEY (lectureId)
 );

CREATE TABLE groups (
  lectureId INT NOT NULL,
  groupNo INT NOT NULL,
  title VARCHAR(10) NOT NULL,
  PRIMARY KEY (lectureId,groupNo),
  FOREIGN KEY (lectureId) REFERENCES lectures (lectureId)
    ON UPDATE CASCADE ON DELETE CASCADE
 );

CREATE TABLE studentListed (
  studentId INT NOT NULL,
  lectureId INT NOT NULL,
  groupNo INT NULL,
  PRIMARY KEY (studentId,lectureId),
  FOREIGN KEY (lectureId) REFERENCES lectures (lectureId) 
    ON UPDATE CASCADE ON DELETE CASCADE,
  FOREIGN KEY (lectureId,groupNo) REFERENCES groups (lectureId,groupNo)
    ON UPDATE CASCADE ON DELETE CASCADE
 );

CREATE TRIGGER GroupDelete BEFORE DELETE ON groups
FOR EACH ROW
  UPDATE studentListed SET studentListed.groupNo = NULL
    WHERE studentListed.lectureId = OLD.lectureId
    AND studentListed.groupNo = OLD.groupNo;

请注意" ON DELETE CASCADE"最后一个外键永远不会导致级联删除,因为Trigger已经通过使相应的行为空来删除了外键引用。

添加:而不是使用" ON DELETE CASCADE"可以使用" ON DELETE SET NULL"使用相同的触发器,然后"讲话"必须是可以为空的,并且应该包含一个" CHECK(讲义不是空的)"确保它永远不会设置为空