CREATE TABLE 中,除了“主码”约束以外,还有其它许多可以包括在CREATE TABLE命令里的约束,允许的完整性约束包括:

    1. not null

    2. unique

    3. check (<谓词>)

一. not null约束

    null值是所有域的成员,因此是sql中每个属性的默认合法值。然而对于一些属性来说,空值可能是不合适的。考虑account关系中的一个无组,其中account_number是空值。这样一个无级为一个未知账户给出了账户信息。它不包含有用的信息。类似地,我们不会希望一个账户的余额为空。在这种情况下,我们希望禁止空值,我们可以通过限定属性account_number和balance的域来排除宿舍,通过如下声明:

 
  
  1. account_number char(10) not null 
  2. ballance numeric(12,2) not null 

    not null的限定禁止在该属性上插入一个空值。任何可能导致向一个声明为not null的属性插入一个空值的数据库修改都会产生错误诊断信息。

    许多情况下我们会希望避免空值,尤其是SQL禁止在关系模式的主码中出现空值。因此,在我们银行的例子中,account关系中如果属性account_number声明为account的主码,则它不能为空。因此不必显式地声明为not null。

    not null跟限定同样可以被用在用户定义域的声明中;由此该域类型的属性不能为空。例如如果我们希望Dollars域不能有空值,我们可以作如下声明:

 
  
  1. create domain Dollars numeric(12,2) not null 

二.unique 约束

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

 
  
  1. unique(Aj1,Aj2,.....Ajn) 

    unique限定指出Aj1,Aj2,......,Ajn属性形成一个候选码;即一个关系中没有两个元组能在所有主码属性上相等。然后候选码属性可以为空,除非它们已经被显示地声明为not null。注意:空值,不等于其它的任何值。

三. check子句

    SQL中的check子句可以用于关系声明和域声明。当用于关系声明时,check子句指定一个谓词P,关系中的所有元组都必须满足该谓词。

    check子句通常应用是保证属性值满足指定条件,由此创建一个强大的类型系统。例如,创建关系branch的create table命令中的一个子句,check(assets > 0)将保证资产值是非负的。

    作为另一个例子,考虑如下语句:

 
  
  1. create table student( 
  2.     name char(15) not null 
  3.     student_id char(10), 
  4.     degree_level  char(15), 
  5.     primary key (student_id) , 
  6.     check(degree_level in ('Bachelors','Masters','Doctorate')) 

    这里我们用check子句来模拟一个枚举类型,通过指定degree_level必须是"Bachelors","Masters","Doctorate"中的一个来实现。

    check子句允许数据模式的设计者指定一个谓词,对类型属于该域的变量所赋的任意值都必须满足该谓词。

    例如:用check子句可以保证小时工资域的值大于某一指定值(如最低工资):

 
  
  1. create domain HourlyWage numeric(5,2) 
  2. constraint wage_value_test check(value >= 6.00) 

    域Hourlywage有一个约束,以保证小时工资数大于或等于6.00 。 子句constraint wage_valu_test是可选的,它用来将该约束命名为wage_value_test。系统用这个名字指出一个更新违反了哪个约束。
    作为另一个例子,使用in子句可以限定一个域只包含指定的一组值:

 
  
  1. create domain AccountType char(10) constant account_type_test 
  2.     check(value in ('Checking','Saving')) 

    由此,check子句保证属性和域能够以有力的方法加以限制,这是大多数编程语言的类型系统都不能允许的。

    前面check条件在一个元组插入或修改的时候可以很容易得到检测。但是,一般而言,由于check条件中允许出现包含其它关系的子查询,check条件可能变得更复杂(也更难检测)。例如,这个约束可以指定作用在关系deposit中:

 
  
  1. check(branch_name in (select branch_name from branch)) 

    这个check条件检测在deposit关系中一个branch_name元组的确是在关系branch中的分行名称。因此这个条件必须不仅仅是在deposit中插入或修改一个元组的时候检测,而且在关系branch改变的时候也要检测(如在关系branch中,当一个元组被删除或修改的情况下。)

    复杂的check条件在我们希望确保数据完整性的时候是很有用的,但要谨慎地使用,因为检测它们的开销很大。