mysql - 多列外键 : Set single column to Null "ON DELETE" instead of all

标签 mysql sql foreign-keys innodb mariadb

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

要求:如果从父项中删除了一行,则相应子项的一列应设置为 NULL,但外键中的两列都不应设置为 NULL。

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

Example/SQL:下面的 SQL 说明了这个例子,但是最后一个语句将不起作用,因为最后一个 FOREIGN KEY 要求 lectureId 和 groupId 都可以为 NULLable,但是使两者都为 NULLable 将意味着删除组也会将 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
 );

最佳答案

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

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

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

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”永远不会导致级联删除,因为触发器已经通过将相应行置空来删除了外键引用。

添加:除了使用“ON DELETE CASCADE”之外,还可以对相同的触发器使用“ON DELETE SET NULL”,但是“lectureId”必须可以为 null,并且应该包含一个“CHECK(lectureId IS NOT) NULL)”以确保它永远不会设置为空

关于mysql - 多列外键 : Set single column to Null "ON DELETE" instead of all,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33735266/

相关文章:

sql - MySQL外键问题

mysql - 将 Group By 应用于 If 语句结果

MySql:SELECT 查询中的计数+1

mysql - 连接 SQL 列中的选择

sql - 选择价格未变化的行

MySQL 索引有两列,其中一列是外键

mysql - 如何为这种情况编写更好的 SQL

mysql - 出现控制命令时的.BAT 文件代码

mysql - 带有日历的事件的 SQL 表

asp.net-mvc - 在 Entity Framework 代码优先中为同一个表定义多个外键