MySQL 跨表约束

标签 mysql triggers constraints

我有三个表,表 A 有一个自动递增的唯一主键,另外两个(表 B 和 C)的主键有一个外键约束,将它们与第一个表的主键联系起来。

我想做一个约束,保持第二个和第三个表中的所有行不能包含任何重复项,并且对于表 A 中的所有记录,在 B 或 C 中都有匹配的记录。

所以基本上类型 A 的记录可以是类型 B 或 C,并且必须是类型 B 或 C。

在 MySQL 中是否可以在没有触发器的情况下进行此约束?还是需要触发器?

感谢您的帮助。

最佳答案

您可以使用“类型”表:

CREATE TABLE Type
  ( type_code CHAR(1) NOT NULL
  , PRIMARY KEY (type_code)
  ) ;

恰好有 2 行(与您需要的不同子类型表一样多:

INSERT INTO Type (type_code)
VALUES ('B'), ('C') ;

父类(super class)型表(包括引用“类型”的列):

CREATE TABLE A
  ( a_id INT NOT NULL AUTO_INCREMENT
  , type_code CHAR(1) NOT NULL
  , PRIMARY KEY (a_id)
  , UNIQUE KEY (type_code, a_id)
  , FOREIGN KEY (type_code)
      REFERENCES Type (type_code)
  ) ;

子类型表(现在引用 A 的主键和 type_code 的组合:

CREATE TABLE B
  ( a_id INT NOT NULL
  , type_code CHAR(1) NOT NULL DEFAULT 'B'
  , PRIMARY KEY (type_code, a_id)
  , FOREIGN KEY (type_code, a_id)
      REFERENCES A (type_code, a_id)
  , CHECK (type_code = 'B')
  ) ;

CREATE TABLE C
  ( a_id INT NOT NULL
  , type_code CHAR(1) NOT NULL DEFAULT 'C'
  , PRIMARY KEY (type_code, a_id)
  , FOREIGN KEY (type_code, a_id)
      REFERENCES A (type_code, a_id)
  , CHECK (type_code = 'C')
  ) ;

如果 MySQL 实现了 CHECK 约束,上面的代码就可以正常工作。但它没有。因此,要绝对确保您的所有规范都得到执行,而不是 'B' 类型的数据被插入到 C 表中,您必须再添加 2 个“类型"表(并删除 MySQL 中无用的 CHECK 约束):

CREATE TABLE TypeB
  ( type_code CHAR(1) NOT NULL
  , PRIMARY KEY (type_code)
  ) ;

CREATE TABLE TypeC
  ( type_code CHAR(1) NOT NULL
  , PRIMARY KEY (type_code)
  ) ;

每行恰好 1 行:

INSERT INTO TypeB (type_code)
VALUES ('B') ;

INSERT INTO TypeC (type_code)
VALUES ('C') ;

和额外的 FK:

ALTER TABLE B
  ADD FOREIGN KEY (type_code)
    REFERENCES TypeB (type_code) ;

ALTER TABLE C
  ADD FOREIGN KEY (type_code)
    REFERENCES TypeC (type_code) ;

有了这些约束,表 A 的每一行都将是 B 或 C 类型,并且将在各自的表(B 或 C)中,而不是在两个表中。

如果您还想确保它们将恰好在一个表中(永远不会既不在 B 也不在 C),那么在插入 A 时应该小心(所有插入都应该通过执行该要求的事务来完成) .

关于MySQL 跨表约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11820151/

相关文章:

sql - 获取 SQL Server 中触发器的调用者

postgresql - 存储月份的数据类型或约束

mysql - 从数据库中选择 id 等于变量的内容

mysql - 当我尝试在 Long 类型的字段上创建主键时出错

mysql - 检查复制类型mysql

sql - postgresql触发器函数中修改OLD为DELETE返回

MySQL 触发器问题

java - 在 Java 中触发异步进程

ios - 如何以编程方式修改 UIButton 的约束

iOS:更改 StackView 中 TextField 的高度(在 StackView 内)