外键(引用)约束

外键约束(也称为引用约束引用完整性约束)可定义表间以及表内必需的关系。

例如,典型的外键约束可能规定 EMPLOYEE 表中的每个职员必须 是一个现有部门的成员,该部门在 DEPARTMENT 表中定义。

引用完整性是数据库的一种状态,在该状态中,所有外键的所有值都有效。 外键是表中的一列或一组列,它的值需要与其父表的行的至少一个主键或唯一键值相匹配。 引用约束是这样一种规则,仅当满足下列其中一个条件时,外键的值才有效:
  • 它们作为父键的值出现。
  • 外键的某些组成部分为空。

要建立此关系,应将 EMPLOYEE 表中的部门号定义成外键,并将 DEPARTMENT 表中的部门号定义成主键。

图 1 显示当两个表之间存在外键约束时,如何阻止具有无效键的记录添加到表中:
图 1。 外键和主键约束
无法将部门号无效的员工添加到员工表。

包含父键的表称为引用约束的父表,包含外键的表被认为是该表的从属表

可以在 CREATE TABLE 语句或 ALTER TABLE 语句中定义引用约束。 引用约束由数据库管理器在执行 INSERT、UPDATE、DELETE、ALTER TABLE、MERGE、ADD CONSTRAINT 和 SET INTEGRITY 语句时强制实施。

引用完整性规则涉及下列术语:
表 1. 引用完整性术语
概念 术语
父键 引用约束的主键或唯一键。
父行 具有至少一个从属行的行。
父表 包含引用约束的父键的表。 表可在任意数目的引用约束中充当父表。 在引用约束中充当父表的表还可以是引用约束中的从属表。
从属表 在其定义中包含至少一个引用约束的表。 表可在任意数目的引用约束中充当从属表。 在引用约束中充当从属表的表还可以是引用约束中的父表。
派生表 作为表 T 的后代的表(如果它是 T 的从属表或是 T 的从属表的后代)。
从属行 具有至少一个父行的行。
派生行 作为行 r 的后代的行(如果它是 r 的从属行或是 r 的从属行的后代)。
引用循环 引用约束的集合,该集合中的每个表都是它自身的后代。
自引用表 在同一引用约束中既充当父表又充当从属表的表。 该约束称为自引用约束
自引用行 一个作为它自己的父代的行。

引用约束的目的是保证表关系得到维护并遵循数据输入规则。 这意味着,只要引用约束有效,数据库管理器就保证,对于子表中其外键列中具有非空值的每行,相应父表中都存在一个其父键中具有匹配值的行。

当 SQL 操作尝试更改数据的方式导致引用完整性受到影响时,可能是违反了引用约束。 例如,
  • 插入操作可能尝试将一个数据行插入到子表中,该行的外键列中的值与相应父表的父键中的值不匹配。
  • 更新操作可能尝试将子表的外键列中的值更改为一个在相应父表的父键中没有匹配值的值。
  • 更新操作可能尝试将父表的父键中的值更改为一个在子表的外键列中没有匹配值的值。
  • 删除操作可能尝试从父表中移除在子表的外键列中具有匹配值的记录。
数据库管理器通过强制执行与每个引用约束关联的一组规则来处理这类情况。 这组规则包括:
  • 插入规则
  • 更新规则
  • 删除规则

插入规则

引用约束的插入规则为:外键的非空插入值必须与父表的父键的某些值相匹配。 如果组合外键的值的任何组成部分为空,那么该值为空。 指定外键时,此规则是隐式的。

更新规则

引用约束的更新规则是在定义引用约束时指定的。 选项有 NO ACTION 和 RESTRICT。 在更新父表的某行或从属表的某行时应用更新规则。

当父键的某列中的值更新时,下列规则适用:
  • 如果从属表中的任何行与该键的原始值相匹配,在更新规则为 RESTRICT 的情况下,会拒绝更新。
  • 如果在更新语句完成时从属表中的任意行没有相应的父键(排除后触发器),当更新规则为 NO ACTION 时,会拒绝更新。

如果更新规则为 RESTRICT,并且存在一个或多个从属行,那么父代唯一键的值不能更改。 但是,如果更新规则为 NO ACTION,并且更新语句完成时每个子代都有父键,那么父代唯一键可以更新。 外键的非空更新值必须等于关系的父表的主键值。

而且,将 NO ACTION 或 RESTRICT 用作引用约束的更新规则将确定何时强制执行约束。 更新规则 RESTRICT 将在所有其他约束之前(包括修改 CASCADE 或 SET NULL 之类的规则的引用约束)执行。 更新规则 NO ACTION 将在其他引用约束之后强制执行。 注意,返回的 SQLSTATE 根据更新规则是 RESTRICT 还是 NO ACTION 而有所不同。

如果是从属行,当指定外键时,NO ACTION 更新规则是隐式的。 NO ACTION 意味着更新语句完成时,外键的非空更新值必须与父表的父键的某些值相匹配。

如果组合外键的值的任何组成部分为空,那么该值为空。

删除规则

引用约束的删除规则是在定义引用约束时指定的。 选项有 NO ACTION、RESTRICT、CASCADE 或 SET NULL。 仅当外键的某些列允许空值时,才能指定 SET NULL。

如果已标识表或已标识视图的基本表为父代,那么选择要删除的行在删除规则 RESTRICT 的关系中一定不能有任何从属项,并且 DELETE 一定不能级联至在删除规则 RESTRICT 的关系中具有从属的后代行。

如果 RESTRICT 删除规则未阻止删除操作,那么会删除所选行。 从属于所选行的所有行也会受到影响:
  • 在删除规则 SET NULL 的关系中充当从属项的所有行的外键的可空列将设置为空值。
  • 在删除规则 CASCADE 的关系中充当从属项的所有行也会被删除,而上述规则将应用于这些行。
将检查删除规则 NO ACTION 以在强制执行其他引用约束后强制所有非空外键引用现有父行。
仅当删除父表的一行后,引用约束的删除规则才适用。 更准确地说,仅当父表的一行成为删除或传播删除操作(在以下一节中定义)的对象并且该行在引用约束的从属表中具有从属项时,此规则才适用。 考虑这样一个示例,其中 P 是父表,D 是从属表,而 p 是充当删除或传播删除操作的对象的父行。 删除规则的工作方式如下:
  • 对于 RESTRICT 或 NO ACTION,发生错误,且不会删除任何行。
  • 对于 CASCADE,删除操作会传播至表 D 中的 p 的从属项。
  • 对于 SET NULL,表 D 中的 p 的每个从属项的外键的每个可空列被设置为空。

在 P 上执行删除操作时可能涉及的任何表都被认为是 delete-connected 到 P。 因此,如果表是 P 的从属表,或从 P 级联删除操作所针对的表的从属表,那么该表将被删除-连接到表 P。

下列限制适用于删除连接关系:

  • 如果一个表在多个表的引用循环中删除连接至它自己,那么该循环不能包含删除规则 RESTRICT 或 SET NULL。
  • 一个表不能既是 CASCADE 关系中的从属表(自引用或者引用另一个表)又与删除规则 RESTRICT 或 SET NULL 具有自引用关系。
  • 当一个表通过多种关系(这些关系具有重叠的外键)删除连接至另一个表时,这些关系必须具有相同的删除规则,并且任何这些关系都不能为 SET NULL。
  • 当一个表通过多种关系(其中一种关系是使用删除规则 SET NULL 指定的)删除连接至另一个表时,此关系的外键定义不能包含任何分布键或 MDC 键列、表分区键列或 RCT 键列。
  • 当两个表通过 CASCADE 关系删除连接至同一个表时,这两个表之间不能互相删除连接(其中删除连接路径以删除规则 RESTRICT 或 SET NULL 结束)。