DB2 约束
约束
关系数据库中二维表的每一列数据除了需要指定数据类型,有时还需要指定一些约束条件,来限制该列能够存储哪些数据。关系数据库中主要存在五种约束(Constraint):非空、唯一、主键、外键、检查。
约束有两个级别:列级别和表级别。如果某个约束只对某个列有限制,就是列级别约束,如果某个约束与多个字段相关,则需要定义成表级别约束。
3.12.1 非空约束
非空(Not Null)约束表示某个字段中不允许出现空值(Null),就规定这个字段使用非空约束,它是一个列级别约束。其定义方式为:
字段名称 数据类型 NOT NULL |
3.12.2 唯一约束
某个字段中不允许出现重复值,就规定这个字段使用唯一(Unique)约束,同样它也是一个列级别的约束。需要注意的是,从 DB2 V9 开始,唯一约束同时也要求非空,即定义了某个字段唯一,则该列当中既不能出现重复值,也不能出现空值。其定义方式为:
字段名称 数据类型 UNIQUE |
3.12.3 主码约束
主码(Primary Key)约束又称为主键约束,是一个或者多个字段的组合,关系数据库要求在一张表中,不能出现完全相同的两行,通常主键就是能够用于区分不同记录的字段或者字段组合。在实际项目中,每张表往往会定义一个编号字段来作为主码。
主码要求同时满足非空和唯一的条件,如果主码是由多个字段组合构成的,每个字段中都不能出现空值,这些字段的组合不能重复。
如果单独一个字段作为主码,它既可以定义成列级别约束,也可以定义成表级别约束。如果是多个字段组合作为主码,必须定义成表级别约束。
列级别主码的定义方式为:
字段名称 数据类型 NOT NULL PRIMARY KEY |
需要注意的是,在定义主码之前必须指定该字段为非空的。
表级别主码的定义方式为:
PRIMARY KEY( 字段列表 ) |
3.12.4 外码约束
外码(Foreign Key)约束又称为外键约束,通常是定义两张表之间的关联的。相关联的两张表一张作为主表,一张作为从表,从表中有一个或者多个字段参照主表中相应的字段,也就是说,从表中这些字段当中只能出现主表中出现过的值(或者是空值),不能出现其他没有出现过的值。下面通过一个例子来讲解外码的创建。
例 3?19 外码约束。
建立两张表,一张为系别表 Department,包括编号(DeptNo)和系名(DeptName)两个字段,一张为学生表 Student,包括学号(StuNo)、姓名(Name)、性别(Sex)和系别(DeptNo),其中学生表的系别字段要参照系别表,同时要求当系别表中某行记录删除时,自动删除学生表中该系的所有学生。
CREATE TABLE Department ( DeptNo CHAR(10) NOT NULL PRIMARY KEY, DeptName VARCHAR(20) NOT NULL ) CREATE TABLE Student ( StuNo CHAR(11) NOT NULL PRIMARY KEY, Name VARCHAR(8) NOT NULL, Sex CHAR(2), DeptNo CHAR(10), FOREIGN KEY(DeptNo) REFERENCES Department(DeptNo) ON DELETE CASCADE ) |
在从表 Student 创建的最后一句中,ON DELETE CASCADE 子句指的是当主表中的数据删除时,从表中对应的数据一起被级联删除。
此处还可以写成 ON DELETE SET NULL,表示主表数据删除时,从表对应数据设置为空值,其他的写法请参见信息中心。
关于外码的创建,有三点需要注意:
一是必须先定义主表,再定义从表;
二是从表所参照的字段在主表中必须是主码或者候选码(有唯一约束的字段);
三是从表中对应字段的数据类型必须与主表中的相同,但字段名称并不要求相同。
3.12.5 检查约束
如果要求某个字段在某个范围内取值,就需要使用检查(Check)约束,它可以是列级别的约束,语法为:
字段名称 数据类型 CHECK( 约束条件 ) |
也可以是表级别的约束,语法为:
CHECK( 约束条件 ) |
3.12.6 其他约束
除了以上五种标准 SQL 定义的约束,DB2 中还扩展了一些约束,比较常用的有缺省值和标识列。
缺省值(Default),又叫做默认值,用于指定某个字段的默认值,当插入数据的时候没有给出值,将使用这个默认值进行填充,它是一个列级别约束,其语法为:
字段名称 数据类型 DEFAULT < 默认值 > |
标识列(Identity),定义在数值型字段上的一种约束,用它可以在插入一行新记录的时候生成一个按照一定规律自动增长的值。
标识列可以有两种生成方式:GENERATED ALWAYS 和 GENERATED BY DEFAULT,下面详细介绍这两种方式的区别。
1 . GENERATED ALWAYS
这种生成方式总是由 DB2 生成值,不能在应用程序或者 SQL 语句中直接提供值。
例 3?20 GENERATED ALWAYS 生成的标识列。
下例说明了通过 GENERATED ALWAYS 生成的标识列如何使用。运行下例之前,首先要把自动提交的选项关闭(db2 +c)。
CREATE TABLE inventory1 ( partno INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 100, INCREMENT BY 1), description CHAR(20) ); INSERT INTO inventory1 VALUES (DEFAULT,‘door‘); ---> 成功,插入了 100,door INSERT INTO inventory1 (description) VALUES (‘hinge‘); ---> 成功,插入了 101,hinge INSERT INTO inventory1 VALUES (102,‘window‘); ---> 失败 ,partno 不能插入值 COMMIT; INSERT INTO inventory1 (description) VALUES (‘lock‘); ---> 成功,插入了 102,lock ROLLBACK; ---> 取消了前一步操作 INSERT INTO inventory1 (description) VALUES (‘frame‘); ---> 成功,插入了 103,frame COMMIT; SELECT * FROM inventory1; 100 door 101 hinge 103 frame |
2 . GENERATED BY DEFAULT
采用这种方式,如果用户没有给标识列提供值,DB2 将自动生成一个值;如果用户给标识列提供了值,DB2 将不再生成值,而是直接使用用户提供的值。使用这种方式,不能保证生成的值是唯一的。
例 3?21 GENERATED BY DEFAULT 生成的标识列。
下例说明了通过 GENERATED BY DEFAULT 生成的标识列如何使用。运行下例之前,同样需要首先把自动提交的选项关闭(db2 +c)。
CREATE TABLE inventory2 ( partno INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 100, INCREMENT BY 1), description CHAR(20) ); INSERT INTO inventory2 VALUES (DEFAULT,‘door‘); ---> 成功,插入了 100,door INSERT INTO inventory2 (description) VALUES (‘hinge‘); ---> 成功,插入了 101,hinge INSERT INTO inventory2 VALUES (102,‘window‘); ---> 成功,插入了 102,window COMMIT; INSERT INTO inventory2 (description) VALUES (102,‘lock‘); ---> 成功,插入了 102,lock INSERT INTO inventory2 (description) VALUES (‘lock‘); ---> 成功,插入了 102,lock ROLLBACK; ---> 取消了前一步操作 INSERT INTO inventory2 (description) VALUES (‘frame‘); ---> 成功,插入了 103,frame COMMIT; SELECT * FROM inventory2; 100 door 101 hinge 102 window 103 frame |
可以使用 IDENTITY_VAL_LOCAL() 函数来获取当前生成列的生成值,它主要是用于在从表中给对应的列插入数据,例如:
INSERT INTO PARENT_TABLE (PK_ID, ... ) VALUES (DEFAULT, ...); INSERT INTO CHILD1_TABLE (...,FK_ID,...) VALUES (....,IDENTITY_VAL_LOCAL(),...); INSERT INTO CHILD2_TABLE (...,FK_ID,...) VALUES (....,IDENTITY_VAL_LOCAL(),...); |
其中 PARENT_TABLE 为主表,PK_ID 为主码,是标识列。而 CHILD1_TABLE 和 CHILD2_TABLE 是参照于主表的从表,其中 FK_ID 是外码,参照主表中的主码。由于外码的取值要在主码所参照的主表中出现,而主表中的主码是由标识列自动生成的,要想知道当前生成的值就需要使用 IDENTITY_VAL_LACAL() 函数。