SQL 完整性约束

完整性约束(integrity constraint)保证授权用户对数据库所做的修改不会导致数据一致性的丢失。因此, 完整性约束防止的是对数据库的意外破坏。这与安全性约束(security constraint)不同,安全性约束防止未经授权的用户访问数据库。
一般来说,一个完整性约束可以是关于数据库的任意谓词。但是,检测任意谓词的代价可能太高。因此,大多数数据库系统允许用户指定那些只需极小开销就可以检测的完整性约束。
完整性约束通常被视为数据库模式设计过程的一部分,并作为用于创建关系的create table命令的一部分被声明。然而,也可以通过使用alter table table-name add constraint命令将完整性约束施加到已有关系上,其中constraint可以是该关系上的任意约束。当这样一条命令被执行时,系统首先保证该关系满足指定的约束。如果满足,那么约束被施加到关系上;如果不满足,则上述命令被拒绝执行。


单个关系上的约束

create table命令还可以包括完整性约束语句。除了主码约束之外,还有许多其他可以包括在create table命令中的约束。允许的完整性约束包括:

  • not null
  • unique
  • check(<谓词>)

非空约束

空值是所有域的成员,它在缺省情况下是SQL中每个属性的合法值。然而对于特定属性来说,空值可能是不合适的。
非空(not null)约束禁止对该属性插入空值,并且它是域约束(domain constraint)的一个示例。可能导致向一个声明为非空的属性插入空值的任何数据库修改都会产生错误诊断信息。
在许多情况下我们希望避免空值。尤其是SQL禁止在关系模式的主码中出现空值。系统默认主码必须是非空,所以主码是不必要显式地声明为非空的


唯一性约束

SQL还支持这种完整性约束:

unique(Aj1 , Aj2 , … , Ajm)

唯一性(unique)声明指出属性Aj1 , Aj2 , … , Ajm形成了一个超码;也就是说,在关系中没有两个元组能在所有列出的属性上取值相同。然而声明了唯一性的属性允许为null,除非它们已被显示地声明为非空。(空值并不等于其他的任何值,所以并不矛盾


check子句

当应用于关系声明时,check(P)子句指定了一个谓词P,关系中的每个元组都必须满足谓词P。
通常用check子句来保证属性值满足指定的条件,实际上是创建了一个强大的类型系统。
check子句允许以有力的方式对属性域加以限制,这是大多数编程语言的类型系统所不能允许的。
在对check子句的求值中空值呈现了一种有趣的特殊情况。如果check子句不为假,则它是满足的,因此计算结果为未知的子句也是满足的如果不需要空值,则必须指定单独的非空约束
check子句可以单独出现,也可以作为属性声明的一部分出现。check子句的位置取决于编码风格。通常来说,对单个属性值的约束与该属性一起列出,而更复杂的check子句则在create table语句的末尾单独列出。
根据SQL标准,check子句中的谓词可以是包括子查询在内的任意谓词。然而,当前还没有一个被广泛使用的数据库产品允许包含子查询的谓词。


引用完整性

我们常常希望保证一个关系(引用关系)中给定属性集合的取值也在另一个(被引用关系)的特定属性集的取值中出现,这种情况称为引用完整性约束,外码是引用完整性约束的一种形式,其中被引用的属性构成被引用关系的主码。
通过使用外码(foreign key)子句,可以将外码指定为SQL的创建表(create table)语句的一部分。
在缺省情况下,在SQL中外码引用的是被引用表的主码属性。SQL还支持一个可以显式指定被引用关系的属性列表的引用子句的版本。
这个指定的属性列表必须声明为被引用关系的超码,要么使用主码约束,要么使用唯一性约束开进行这种声明。在更为普遍的引用完整性约束形式中,被引用的属性不必是候选码,但这样的形式不能在SQL中直接声明。SQL标准提供了另外的结构用于实现这样的约束。但是,任何广泛使用的数据库系统都不支持这些替代结构。
请注意外码必须引用一组兼容的属性,也就是说,属性数量必须相同,并且相应属性的数据类型必须兼容。
当违反引用完整性约束时,通常的处理是拒绝执行导致破坏完整性的操作(即执行更新操作的事务被回滚)。但是,在外码(foreign key)子句中可以指明如果被引用关系上的删除或更新操作违反了约束,那么系统必须采取一些措施来改变引用关系中的元组以恢复完整性约束,而不是拒绝这样的操作
请考虑course关系上一个完整性约束的如下定义:

create table course
(...
foreign key(dept_name)references department
              on delete cascade
              on update cascade,
...);

由于有了与外码声明相关联的级联删除( on delete cascade )子句,如果删除 department 中的一个元组导致违反了这种引用完整性约束,则系统并不拒绝该删除,而是对 course 关系做“级联( cascade )”删除,即删除引用了被刪除系的元组。类似地,如果更新被约束引用的字段时违反了约束,则系统并不拒绝更新操作,而是将 course 中引用元组的 dept_name 字段也改为新值。 SQL 还允许外码( foreign key )子句指定除级联以外的其他动作,如果约束被违反,可将引用域(这里是dept_name)置为 null (通过用 set null 代替 cascade ),或置为该域的缺省值(通过使用 set default )
如果存在跨多个关系的外码依赖链,则在链的一端所做的删除或更新可能级联传至整个链上
如果一个级联更新或删除所导致的对约束的违反不能通过进一步的级联操作来解决,则系统就中止该事务。其结果是,该事务所做的所有修改以及它的级联动作都将被撤销
空值使得 SQL 中引用完整性约束的语义复杂化了。外码中的属性允许为null,只要它们没有另外被声明为非空。如果在给定元组的外码的所有列上均取非空值, 则对该元组采用外码约束的通常定义。如果任一外码列为 null ,则该元组被自动定义为是满足约束的。


给约束赋名

我们可以为完整性约束赋予名称。如果我们想要删除先前定义的一个约束,则这样的名称是很有用的。
为了命名约束,我们在约束的前面使用关键字constraint和我们希望为其赋予的名称。
例如,如果我们希望将名称minsalary赋给instructor的salary属性上的check约束,那么可以将对salary的声明修改为:

salary numeric(8,2),constraint minsalary check(salary>29000),

之后,如果我们决定不再需要这个约束,那么可以写为:

alter table instructor drop constraint minsalary;

如果名称缺失,需要使用特定于系统的功能来识别出约束的系统分配名称。并非所有的系统都支持这样的功能,但是比如在Oracle中,系统表user_constraints就包含了这样的信息。


复杂check条件与断言

在SQL标准中还有其他的结构用于指定大多数系统当前不支持的完整性约束。
正如SQL标准所定义的,check子句中谓词可以是包含子查询的任意谓词。
复杂的check条件在我们希望确保数据完整性的时候是有用的,但它们的检测开销可能会很大。
一个断言(assertion)就是一个谓词,它表达了我们希望数据库总能满足的一个条件。
SQL中的断言采用如下形式:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alkali!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值