Prayer

在一般中寻求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

DB2数据库的约束

Posted on 2010-04-15 23:58 Prayer 阅读(2466) 评论(0)  编辑 收藏 引用 所属分类: DB2
 约束被 DB2 Universal Database(TM)(DB2 UDB)用来对数据实施业务规则。本文描述了下列类型的约束:非空(NOT NULL)、惟一、主键、外键、表检查。此外,还有另一种名为信息约束(informational constraint)的约束。与上面所列的这五种约束类型不同的是,信息约束不是由数据库管理器实施的,但是 SQL 编译器可用它来提高查询性能。在这篇文章中,我将只关注上面所列的这几类约束,而不会讨论信息约束。

  您可以在创建一个新表时定义一个或多个 DB2 UDB 约束,也可以稍后通过更改表来定义它们。CREATE TABLE 语句是十分复杂的;所以尽管实际上其选项中只有一小部分是用于定义约束的,但是当在语法图(图1和 图2)中进行查看时,那些选项本身看上去就相当复杂。通过 DB2 Control Center 可使约束管理更简单、方便。

  图 1. CREATE TABLE 语句的部分语法,显示了用于定义约束的子句

 

  约束定义与它们所应用的数据库相关联,并存储在数据库目录中(表1)。您可以查询数据库目录来检索并查看该信息。您可以从命令行直接进行(请记住要首先建立数据库连接),同样,您会发现通过 Control Center 来访问这些信息会更方便。

  可将所创建的约束像对待其他数据库对象一样进行处理。它们具有名称和关联模式(creator ID),并且在有些情况下还能被撤销(删除)。

  图 2. CREATE TABLE 语句的部分语法,显示了用于定义约束的子句(续)

 

  表1. 数据库目录中的约束信息。要运行成功,对目录的查询需要建立数据库连接。 目录视图 视图列 描述 查询实例

  SYSCAT.CHECKS为每个表检查约束包含一行记录db2 select constname, tabname, text from syscat.checks

  SYSCAT.COLCHECKS为表检查约束所引用的每一列包含一行记录db2 select constname, tabname, colname, usage from syscat.colchecks

  SYSCAT.COLUMNSNULLS指明一列是可为空(Y)还是不可为空(N)db2 select tabname, colname, nulls from syscat.columns where tabschema = ''MELNYK'' and nulls = ''N''

  SYSCAT.CONSTDEP为某些其他对象上的约束的每个依赖性包含一行记录db2 select constname, tabname, btype, bname from syscat.constdep

  SYSCAT.INDEXES为每个索引包含一行记录db2 select tabname, uniquerule, made_unique, system_required from syscat.indexes where tabschema = ''MELNYK''

  SYSCAT.KEYCOLUSE为惟一、主键或外键约束定义的键中所包含的每个列包含一行记录db2 select constname, tabname, colname, colseq from syscat.keycoluse

  SYSCAT.REFERENCES为每个参照约束包含一行记录db2 select constname, tabname, refkeyname, reftabname, colcount, deleterule, updaterule from syscat.references

  SYSCAT.TABCONST为每个惟一(U)、主键(P)、外键(F)或表检查(K)约束包含一行记录db2 select constname, tabname, type from syscat.tabconst

  SYSCAT.TABLESPARENTS该表的父表数目(该表在其中充当子表的参照约束数目)db2 "select tabname, parents from syscat.tables where parents > 0"

  SYSCAT.TABLESCHILDREN该表的子表数目(该表在其中充当父表的参照约束数目)db2 "select tabname, children from syscat.tables where children > 0"

  SYSCAT.TABLESSELFREFS该表的自引用参照约束数目(该表在其中既充当父表又充当子表的参照约束数目)db2 "select tabname, selfrefs from syscat.tables where selfrefs > 0"

  SYSCAT.TABLESKEYUNIQUE在该表上所定义的惟一约束(除了主键)的数目db2 "select tabname, keyunique from syscat.tables where keyunique > 0"

  SYSCAT.TABLESCHECKCOUNT在该表上所定义的检查约束的数目db2 "select tabname, checkcount from syscat.tables where checkcount > 0"

  “不能为空值!” - 非空约束

  非空约束(NOT NULL constraint)防止向一列添加空值。这就确保了该列在表中每一行都存在一个有意义的值。例如,SAMPLE 数据库中 EMPLOYEE 表的定义包括 LASTNAME VARCHAR(15) NOT NULL ,这就确保每行都将包含一个雇员的姓。

  要判断一列是否可为空,您可以查阅该表的数据定义语言(DDL)(可通过调用 db2look 工具来生成);您也可以使用 DB2 Control Center(图3和图4);或者您还可以查询数据库目录(清单1)。

  图 3. DB2 Control Center 的内容窗格中显示了在其对象树中选中的关联了特定数据库的表。该列表是在 melnyk 模式上筛选的。

 

  DB2 Control Center 让您方便地访问诸如表这样的数据库对象。图 3 显示了 SAMPLE 数据库中的用户表。当在对象树中选中 Tables 时,它们就会出现在其内容窗格中。如果选择 EMPLOYEE 表,我们可以打开 Alter Table 窗口来查看表定义,包括列属性(图 4)。

  图 4. Alter Table 窗口提供了一个方便方式来查看表属性。

 

  清单 1. 查询数据库目录以判断哪些数据库列可为空

  db2 select tabname, colname, nulls

  from syscat.columns

  where tabschema = ''MELNYK'' and nulls = ''N''

  “仅单独存在” - 惟一约束

  惟一约束(unique constraint)防止一个值在表中的特定列里出现不止一次。它还防止一组值在特定的一组列里出现不止一次。必须将惟一约束中所引用的列定义为非空(NOT NULL)。可在 CREATE TABLE 语句中使用 UNIQUE 子句(图1和图2)或者在如下的 altER TABLE 语句中定义惟一约束。

  清单 2. 创建惟一约束。除了 ORG_TEMP 中的 LOCATION 列不能为空且在其上定义了惟一约束之外,ORG_TEMP 表与 SAMPLE 数据库中的 ORG 表是相同的。

  db2 create table org_temp (

  deptnumb smallint not null,

  deptname varchar(14),

  manager smallint,

  division varchar(10),

  location varchar(13)

  not null)

  db2 alter table org_temp

  add unique (location)

  db2 insert into org_temp

  values (10, ''Head Office'', 160, ''Corporate'', ''

  New York'')

  DB20000I The SQL command completed successfully.

  db2 insert into org_temp

  values (15, ''New England'', 50, ''Eastern'', ''

  New York'')

  SQL0803N One or more values in the INSERT statement, UPDATE statement, or

  foreign key update caused by a DELETE statement are not valid because the

  primary key, unique constraint or unique index identified by "1" constrains

  table "MELNYK.ORG_TEMP" from having duplicate rows for those columns.

  SQLSTATE=23505

  惟一约束通过防止无意的复制有助于确保数据的完整性。本例中,它防止插入第二条指定 New York 为该组织某部门位置的记录。惟一约束是通过惟一索引来实施的。

  “头号人物!” - 主键约束

  主键约束(primary key constraint)确保了表中构成主键的一列或一组列的所有值是惟一的。主键用于识别表中的特定行。每个表只能有一个主键,但可以有几个惟一键。主键约束是惟一约束的特例,它是通过主索引来实施的。

  必须将主键约束中所引用的列定义为非空(NOT NULL)。可在 CREATE TABLE 语句中使用 PRIMARY KEY 子句(图1和图2)或者在如下的 altER TABLE 语句中定义主键约束。

  清单 3. 创建主键约束。EMPLOYEE 表中的 EMPNO 列不能为空,并可在其上定义主键约束。

  db2 alter table employee

  add primary key (empno)

  您也可以使用 DB2 Control Center 来定义表上的主键约束(图5)。

  图 5. Alter Table 窗口提供了一个方便方式来定义表上的主键约束。从 available columns 的列表中选择一个或多个列并单击按钮以将选中的列名移至 primary key columns 列表中。选中的列必须不可为空。

 

  “都是相关的!” - 外键约束

  外键约束(foreign key constraint)有时候称作参照约束。 参照完整性(referential integrity)被定义为“数据库的所有外键值都是有效的状态”。那外键又是什么呢? 外键(foreign key)是指表中的一列或一组列,其值必须至少匹配其父表中一行的一个主键或惟一键值。这真正意味着什么呢?它实际上并非如听起来那般复杂。简单来说,它意味着如果表(T2)中的一列(C2)存在值匹配另一个表(T1)中的一列(C1)的值, 并且 C1 是 T1 的主键,那么 C2 就是 T2 中的外键列。将包含了父键(主键或惟一键)的表称为 父表(parent table),而将包含了外键的表称为 子表(dependent table)。让我们来考虑一个实例。

  SAMPLE 数据库中的 PROJECT 表有一个称为 RESPEMP 的列。该列中的值表示负责该表中所列的每个项目的雇员编号。RESPEMP 是不能为空值的。因为该列对应了 EMPLOYEE 表中的 EMPNO 列,并且我们知道 EMPNO 是 EMPLOYEE 表的主键,RESPEMP 就可以定义为 PROJECT 表中的外键(清单 4)。这将确保今后对 EMPLOYEE 表进行的删除不会让 PROJECT 表包含“不存在的”项目负责雇员。

  可在 CREATE TABLE 语句中使用 FOREIGN KEY 子句(图 1 和图 2)或者在如下的 altER TABLE 语句中定义外键约束。

  清单 4. 创建外键约束。

  db2 alter table project

  add foreign key (respemp)

  references employee on delete cascade

  REFERENCES 子句指向此参照约束的父表。定义外键约束的语法包括 规则从句(rule-clause),在其中您可以从参照完整性角度告诉 DB2 如何处理 update 或 delete 操作(图1)。

  将以标准方式处理 Insert 操作,您不能对其进行控制。参照约束的 插入规则(insert rule) 是指外键的插入值必须匹配其父表中的某个父键值。这是有道理的,并且与上述内容一致。如果向 PROJECT 表插入一条新记录,那么该记录必须包含对 EMPLOYEE 表中一个现有记录的引用(通过父-外键关系)。

  参照约束的 更新规则(update rule) 是指 外键(foreign key)的更新值必须匹配其父表中的某个父键值,并且当完成 父键(parent key)上的 update 操作时,所有的外键值必须有匹配的父键值。总的来说,这意味着不能存在任何“孤儿”;每个子表必须有一个父表。

  参照约束的 删除规则(delete rule) 是当从父表中删除一行时应用的,并且依赖于在定义参照约束时所指定的选项。如果指定了 RESTRICT 或 NO ACTION 子句,就不能删除任何一行。如果指定了 SET NULL 子句,则会将每个可为空的外键列设置为 null。然而,如果在创建参照约束时指定了 CASCADE 选项,那么 delete 操作将会被传播到父表的各子表上。因为已指定这些子表与父表是 删除关联的(delete-connected。

  下列实例说明了这些观点。

  清单 5. 演示了外键约束中的更新规则和删除规则。

  db2 update employee set empno = ''350'' where empno = ''000190''

  DB20000I The SQL command completed successfully.

  db2 update employee set empno = ''360'' where empno = ''000150''

  SQL0531N The parent key in a parent row of relationship

  "MELNYK.PROJECT.SQL040103212526610" cannot be updated. SQLSTATE=23504

  db2 "select respemp from project where respemp < ''000050'' order by respemp"

  RESPEMP

  -------

  000010

  000010

  000020

  000030

  000030

  db2 delete from employee where empno = ''000010''

  DB20000I The SQL command completed successfully.

  db2 "select respemp from project where respemp < ''000050'' order by respemp"

  RESPEMP

  -------

  000020

  000030

  000030

  父表(EMPLOYEE)中为“000190”的 EMPNO 值 可以被更改,因为子表(PROJECT)中不存在为“000190”的 RESPEMP 值。然而,对于为“000150”的 EMPNO 值就不是这样的了,它在 PROJECT 表中有匹配的外键值,因而不能被更新。指定了 CASCADE 选项的删除规则确保了当从 EMPLOYEE 表中删除主键值时,删除关联的 PROJECT 表将丢失包含相匹配的外键值的所有记录行。

  #p#“检查和再次检查” - 表检查约束

  表检查约束(table check constraint)对将要添加到表中的数据实施已定义的限制。例如,一个表检查约束可确保每当在 EMPLOYEE 表中添加或更新电话分机时,雇员的电话分机号码都正好为四位数字。可在 CREATE TABLE 语句中使用 CHECK 子句(图1和图2)或者在如下的 altER TABLE 语句中定义表检查约束。

  清单 6. 创建表检查约束。PHONENO_LENGTH 约束确保向 EMPLOYEE 表添加的电话分机正好为四位数字。

  db2 alter table employee

  add constraint phoneno_length check (length(rtrim(phoneno)) = 4)

  您也可以使用 DB2 Control Center 来定义表检查约束(图 6)。

  图 6. Alter Table 窗口提供了一个方便方式来定义一列上的表检查约束。

 

  单击 Add 按钮以定义新约束(将打开 Add Check Constraint 窗口),或者单击 Change 按钮以修改在列表中选中的现有的约束(图7)。

  图 7. Change Check Constraint 窗口让您修改现有的检查条件。

 

  如果表中的现有行包含违反新约束的值,您就不能创建此表检查约束(图 8)。在适当更新了那些不兼容的值之后,您就可以成功添加或修改此约束了。

  图 8. 如果新的表检查约束与表中现有的值不兼容,则会返回一条错误。

 

  使用 SET INTEGRITY 语句可以打开或者关闭表检查约束。这将非常有用,例如,当在给表加载大型数据的期间优化性能时。清单 7 呈现了一个简单场景,展示了使用 SET INTEGRITY 语句的一种可能方式。本例中,将雇员“000100”的电话分机更新为 123,然后关闭 EMPLOYEE 表的完整性检查。在 EMPLOYEE 表上定义要求电话分机值为 4 位数字的检查约束。创建名为 EMPL_EXCEPT 的异常表;这个新表的定义是 EMPLOYEE 表的镜像。然后打开完整性检查,而违反检查约束的行将被写入异常表中。对这些表的查询将证实有问题的行现在仅存在于异常表中。

  清单 7. 使用 SET INTEGRITY 语句来延迟约束的检查。

  db2 update employee set phoneno = ''123'' where empno = ''000100''

  db2 set integrity for employee off

  db2 alter table employee add constraint phoneno_length check (length(rtrim(phoneno)) = 4)

  db2 create table empl_except like employee

  db2 set integrity for employee immediate checked for exception in employee use empl_except

  SQL3602W Check data processing found constraint violations and moved them to

  exception tables. SQLSTATE=01603

  db2 select empno, lastname, workdept, phoneno from empl_except

  EMPNO LASTNAME WORKDEPT PHONENO

  ------ --------------- -------- -------

  000100 SPENSER E21 123

  1 record(s) selected.

  结束语

  我们已经探索了 DB2 Universal Database 所支持的不同类型的约束:非空(NOT NULL)约束、惟一约束、主键约束、外键(参照)约束以及表检查约束。我们展示了 DB2 UDB 是如何使用约束来对数据实施业务规则以及帮助维护数据库完整性的。我们还讲解了如何使用命令行和 DB2 Control Center(和如何查询数据库目录)来有效地管理约束。


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理