4.4.7 复杂check条件与断言

4.4.7 复杂check条件与断言

复杂check条件

本节描述SQL标准所支持的另外一些用于声明完整性约束的结构。然而,读者应该注意的是,这结构目前还没有被大多数数据库系统支持。
正如SQL标准所定义的, check子句中的谓词可以是包含子查询的任意谓词。如果一个数据库实现支持在check子句中出现子查询,我们就可以在关系section上声明如下所示的参照完整性约束:

1
check( time_slot_id in( select time_slot_id from time_slot ))

这个check条件检测在section关系中每个元组的time_slot_id的确是在time_slot关系中某个时间段的标识。
因此这个条件不仅在section中插入或修改元组时需要检测,而且在time_slot关系改变时也需要检测(如在time_slot关系中,当一个元组被删除或修改的情况下)。
在我们的大学模式上,另一个自然的约束是:每个课程段都需要有至少一位教师来讲授
为了强制实现此约束,一种方案是声明section关系的属性集(course_d,seed, semester,yea)为外码,它参照teaches关系中的相应属性。遗憾的是,这些属性并未构成teaches关系的主码。如果数据库系统支持在check约束中出现子查询的话,可以使用与time_slot属性类似的check约束来强制实现上述约束。
复杂check条件在我们希望确保数据完整性的时候是很有用的,但其检测开销可能会很大。例如check子句中的谓词不仅需要在section关系发生更新时计算,而且也可能在time_slot关系发生更新时检测,因为time_slot在子查询中被引用了。

断言

一个断言(assertion)就是一个谓词,是一种命名约束,它表达了数据库状态必须满足的逻辑条件
**域约束参照完整性约束是断言的特殊形式**。

断言 示例

我们前面用大量篇幅介绍了这几种形式的断言,是因为它们容易检测并且适用于很多数据库应用。但是,还有许多约束不能仅用这几种特殊形式来表达。如有两个这样的例子:

  • 对于student关系中的每个元组,它在属性tot_cred上的取值必须等于该生所成功修完课程的学分总和。
  • 每位教师不能在同一个学期的同一个时间段在两个不同的教室授课。

SQL中的断言为如下形式:

1
create assertion <assertion-name> <check predicate>;

第一个断言 实现

1
2
3
4
5
6
7
8
9
10
11
12
create assertion credits_earned_constraint check(
not exists(
select ID
from student
where tot_cred<>(
select sum(credits)
from takes natural join course
where student.ID= takes.ID
and grade is not null
and grade <>'F'
)
))

只有不破坏断言的数据库修改才被允许

当创建断言时,系统要检测其有效性。如果断言有效,则今后只有不破坏断言的数据库修改才被允许。如果断言较复杂,则检测会带来相当大的开销。因此,使用断言应该特别小心。
由于检测和维护断言的开销较大,一些系统开发者省去了对一般性断言的支持,或者只提供易于检测的特殊形式的断言。
目前,还没有一个广泛使用的数据库系统支持在check子句的谓词中使用子查询或create assertion结构

可以通过触发器来实现和断言等价的功能

然而,如果数据库系统支持触发器的话,可以通过使用触发器来实现等价的功能,
触发器将在5.3节介绍,5.3节还将介绍如何用触发器来实现time_slot_id上的参照完整性约束。

MySQL不支持断言create assertion

经过我的测试MySQL 8.0好像不支持create assertion断言。