16. 建立与使用默认值、条件约束及规则
默认值
条件约束
规则对象
本章总结
默认值、条件约束及规则对象皆是您可以在数据表的数据行定义中的选择性属性。在 第15章 ,曾学习了使用如何用ALTER TABLE命令替数据表新增具有默认值的数据行。本章则涵盖设立及修改默认值之方式。回顾一下,设定 默认值 (default)指的是在一没有明确设定值的数据行中,输入一明确的值。 条件约束 (constraint)则是提供了用于辨识有效数据行值的方法(为了拒绝无效的值)。本章将介绍五种类型的条件约束值及如何使用T-SQL及Microsoft SQL Server Enterprise Manager来设立和修改默认值及条件约束的方法,不过,使用Enterprise Manager会较为简单。
默认值
下述状况得以解释为何需要在数据表的数据行中设立默认值。例如您如果想在含有一个或多个可为NULL数据行的数据表中插入数据列,则这些数据行将会被输入为NULL值。但是如果这些数据行被定义为NOT NULL,并且于插入数据列时并未替该批数据行提供值,那么将会有一条错误讯息提醒您NULL无法被插入该批资料行中。此时默认值即可发挥其功效。默认值可在此时替代NULL值,以避免产生错误讯息。
Microsoft SQL Server 7.0允许您为数据表中的每一数据行定义一个默认值。具有timestamp数据型别或IDENTITY、ROWGUIDCOL属性的数据行不能定义默认值,因为这些数据行必须是特殊的值。 默认值 定义中指定的值也必须与数据行中的数据型别是兼容的。
有几种建立和修改默认值定义的方式。在这部份,我们首先介绍如何以T-SQL于建立数据表时定义一个默认值,以及如何透过新增或修改默认值来修改数据行;之后则会介绍以Enterprise Manager来执行相同的工作。在 第15章 里我们曾介绍如何替数据表新增有默认值的数据行,以及此数据行对数据表中现存的数据列所产生的影响。在此,我们将提供一范例以详述可用的选项及新增默认值对数据表中现存数据行的影响。
使用T-SQL来定义和修改默认值
您可以用下列三项陈述式之一为数据行定义默认值:CREATE TABLE、ALTER TABLE或CREATE DEFAULT。SQL Server 2000使用CREATE DEFAULT来建立 预设 对象,保持向后兼容性。使用这种方式时,SQL Server把数据表和对象分开储存,因此必须透过系统预存程序sp_bindefault把对象系结到数据表上。删除数据表时,DEFAULT定义自动从数据表中解除系结,但是 预设 对象仍然存在。在使用CREATE TABLE或ALTER TABLE时,SQL Server会把 预设 对象定义和数据表一同储存,如果数据表被删除,预设对象也会自动被删除,而不须再采取其它操作步骤。因此,通常不建议使用CREATE DEFAULT。然而,当对多个数据行使用相同的默认值时,使用 预设 对象也可能会带来好处。
当执行T-SQL时,应使用SQL Query Analyzer,因其执行结果可显示在使用者图形接口上。此项功能比在命令窗口内执行更方便使用者阅读。
使用CREATE TABLE建立默认值
使用CREATE TABLE命令在数据行中建立默认值是较常用的标准技巧。以下的陈述式在MyDB中建立一有默认值的数据表,并同时定义了两个数据行:A数据行为char类型;B数据行为int类型。
USE MyDB
CREATE TABLE MyTABLE
(
columnA char(15) NULL DEFAULT 'n/a',
columnB int NULL DEFAULT 0
)
GO
columnA中的默认值n/a与该数据行的char数据型别兼容;相同的,columnB中的默认值0和该数据行的int数据型别兼容。如果我们在数据表中插入一数据列而没有为columnA及columnB的两个数据行指定数值,则默认值会被自动取用。所以若要该数据行保持NULL,则要明白表示要插入NULL值。因为此两数据行皆可包含NULL值,所以欲插入NULL值是被允许的。但若数据行定义为NOT NULL,则不能插入NULL值。
使用ALTER TABLE修改默认值
使用ALTER TABLE命令可以修改数据行中的默认值定义或新增一数据行。若要更改已经定义的默认值数据行,首先必须删除已经有的默认值,然后新增一个新的默认值(若您使用的是Enterprise Manager就会较为简单,因为使用Enterprise Manager就不需执行删除的步骤)。
如果用CREATE TABLE命令建立未命名的默认值,或使用Enterprise Manager(将在本章后面部份介绍),SQL Server将自动替默认值命名。要知道SQL Server为默认值分配了什么名字,以便可以使用T-SQL删除它,您可执行sp_help程序如下:
USE MyDB
GO
sp_help MyTable
GO
所有MyTable的默认值名称皆列示在图16-1中的constraint_name资料行下面:
图16-1 sp_help程序的输出
假设我们要把columnA的默认值从n/a改成not applicable。记住首先必须删除存在的默认值然后再新增一个新的。下述命令即可删除默认值:
ALTER TABLE MyTable
DROP CONSTRAINT DF_MyTable_columnA_2B3F6F97
现在您可以使用下述命令新增一个默认值,这次由我们自己命名,:
ALTER TABLE MyTable
ADD CONSTRAINT DF_MyTable_columnA
DEFAULT "Not applicable" FOR columnA
GO
当变更已存在的默认值时,所有现存的列将保持原始的默认值。只有新插入的列会使用新的默认值。
如 第15章 所述,您也可以用ALTER TABLE命令为已有的数据表新增完整的新数据行,如下所示:
ALTER TABLE MyTable
ADD columnC tinyint NOT NULL DEFAULT 13
GO
现在MyTable范例数据表已新增了数据行columnC数据行,其默认值为13。因为columnC是定义为NOT NULL的新数据行,数据表中现存数据行的新数据行将会被分配为默认值13。
如果新数据行允许被设定为NULL值,数据表中现存数据行的新数据行则会被分配为NULL值。若我们希望用默认值而不是NULL插入已存在的列,则应该使用DEFAULT中的WITH VALUES选项,如下所示:
ALTER TABLE MyTable
ADD columnC tinyint NULL DEFAULT 13 WITH VALUES
GO
WITH VALUES命令会强行使MyTable中所有现存列的新数据行接受默认值13来代替原来的NULL值。
现在,我们已经学习了如何建立与数据表储存在一起的DEFAULT定义。下面我们将学习如何用CREATE DEFAULT来建立一个和数据表分开储存的 预设 对象。
CREATE DEFAULT和sp_bindefault
您还可以使用T-SQL CREATE DEFAULT命令来建立Default对象,进而新增或修改现存数据行的默认值。建立默认值对象后,使用系统预存程序sp_bindefault可以把它系结至数据行或系结至使用者自订的数据型别上。如前所述,在SQL Server 2000中保留这种方法的目的是为了向后兼容性,因此它不是很好的方法。但是,如果要在不同的数据表中使用相同的默认值数据行,此方法则较为有效。
下面介绍一个例子,使用CREATE DEFAULT来建立名称为DF_not_applicable的默认值对象,其值为n/a。在MyDB数据库中建立该 预设 对象,并系结至MyTable的columnA上(假定数据表中现在不存在默认值)。使用CREATE DEFAULT的语法如下:
CREATE DEFAULT default_name AS constant_expression
sp_bindefault的语法如下:
sp_bindefault 'default_name' table.column | user_defined_datatype
[", futureonly"]
参数default_name是 预设 对象的名称。Table.column是指定要分配预设对象的数据行。
下面的T-SQL陈述式能建立范例的预设对象,并把它系结至MyTable的columnA上:
USE MyDB
GO
CREATE DEFAULT DF_not_applicable AS 'n/a'
GO
sp_bindefault "DF_not_applicable", "MyTable.columnA"
GO
如果columnA中已经存在默认值,执行sp_bindefault时,SQL Server将传回一条错误讯息,通知您不能系结 预设 对象到已经具有默认值的数据行上。您首先须删除原默认值,然后把新的预设对象系结至该数据行上(使用DROP DEFAULT删除预设对象的过程将在本节后面介绍)。
您还可以建立一预设对象并将此对象与使用者自订数据型别系结起来。系结预设对象到使用者自订数据型别时,您可以使用sp_bindefault的futureonly选项。这一选项防止现存的使用者自订型别数据行接受这个新的默认值,而只有新建立的使用者自订型别的数据行才能接受其相关联的默认值。如果没有指定futureonly,SQL Server将默认值系结到所有已经存在的和新建立的使用者自订类型的数据行上。
例如,让我们建立一个名称为area_code的使用者自订型别和名称为DF_area_code的默认值对象,其值为786;然后系结默认值到该使用者自订数据型别上(使用者自订数据型别的建立在 第10章 介绍过)。因为这是新的使用者自订数据型别,因此目前还没有数据行,也就不需要futureonly选项,但我们依然保留它,因为保留它不会有什么影响。该陈述式将如下所示:
sp_addtype "area_code", "char(3)", "NOT NULL"
GO
CREATE DEFAULT DF_area_code AS 786
GO
sp_bindefault "DF_area_code", "area_code", "futureonly"
GO
要检视 预设 对象的数据型别,可使用sp_help系统程序,如图16-2所示。
图16-2 sp_help的Query Analyzer结果。
sp_unbindefault
要从数据行或使用者自订资料型别中解除系结预设对象,您可以使用sp_unbindefault。例如要解除MyTable中与columnA数据行系结的默认值:sp_unbindefault,其陈述式如下:
sp_unbindefault "MyTable.columnA"
GO
使用下列陈述式,从使用者自订的数据型别area_code中解除系结默认值:
sp_unbindefault "area_code"
GO
当执行以上程序,所有已经由使用者自订数据型别area_code的默认值属性将会同时移除。
您可以使用不同的sp_bindefault陈述式将预设对象系结到多个数据行中。同样的,只要在不删除预设对象的情形下,您可以随意地解除或系结某个数据行的预设。使用DROP DEFAULT陈述式,可以完全删除一个 预设 对象,如下所示:
DROP DEFAULT DF_area_code
GO
一旦删除了预设对象,就无法再取回。如果要再次使用,必须使用CREATE DEFAULT重新建立对象。
使用Enterprise Manager定义及修改默认值
正如 第15章 所示,使用Enterprise Manager建立和修改数据表可能是最简单的方法。用Enterprise Manager建立或修改数据表或数据行时,SQL Server会自动执行适当的T-SQL命令替您完成任务(关于如何使用Enterprise Manager按部就班地建立数据表,请参阅 第10章 )。这部分将学习如何用Enterprise Manager指定默认值定义和修改默认值数据行的详细内容,以及如何建立预设对象。让我们从指定及修改默认值定义的例子讲起。
指定及修改默认值定义
假设在MyDB数据库中有一个名为Product_Info的数据表。数据表的结构如图16-3所示(使用Enterprise Manager建立数据表的说明请参阅 第10章 )。
图16-3 Product_Info数据表的 设计数据表 窗口
要定义默认值,只需在 默认值 标题下的储存格中键入数据行的默认值。注意图16-3中Desciption数据行的默认值定义为 ' n/a ',这只是表示目前尚未指定该项产品的特征。同时要注意默认值被括在小括号中-Enterprise Manager会在您储存数据表时自动新增以上默认值。
变更默认值也很简单。仅需用新默认值取代原默认值,再按一下 存盘 按钮将操作储存即可。图16-4显示把Desciption的默认值变更为'not available';图16-5显示在Product_Name新增一个默认值general merchandise。
________________________________________
说明
在 默认值 储存格中输入字符串,必须放在单引号中,否则储存时会显示SQL Server的错误讯息。
________________________________________
图16-4 设计数据表窗口,显示修改的默认值
图16-5 设计数据表窗口,显示新增的默认值
与T-SQL类似,使用Enterprise Manager新增或修改现存数据行上的默认值时,并不影响数据表中现存的数据列,只有新插入的数据列会使用新的默认值。如果替数据表新增一个数据行并指定一个默认值,在默认值不允许为NULL值的情况下,任何现存数据列中的数据将得到新数据行的默认值;如果允许为NULL值,则现存列中的新数据行将会分配为NULL值。要使新数据行允许为NULL值,并把默认值强行插入到所有现存列中,请参考本章前面 〈使用ALTER TABLE修改默认值〉 部分介绍的方法。
建立和管理预设对象
您也可以使用Enterprise Manager来建立预设对象和检视已有的预设物件。要检视已有的预设对象,开启Enterprise Manager,展开要使用的服务器和数据库,按一下 预设 。所有现存的预设对象将显示在右边窗格中,如图16-6所示。注意,您将可以看到在本章前面用CREATE DEFAULT建立的DF_not_applicable及DF_area_code预设对象。
图16-6 检视现存的预设物件
要使用Enterprise Manager建立新的预设对象,并关联预设对象到数据行或使用者自订数据型别上,须遵循下列步骤:
1. 展开服务器和数据库,在 预设 上按右钮,并在快捷菜单上选择 新增预设 ,以显示出 预设属性 窗口,如图16-7所示。把此预设对象命名为DF_none,并分配 ' none ' 为其值。完成操作后按一下 确定 。
图16-7 预设属性窗口
2. 要系结预设对象到使用者自订数据型别或某一数据行上,在Enterprise Manager右边窗格中的默认值名称(本例是DF_none)上按右钮,并从快捷菜单中选择 内容 。 预设属性 窗口将再次出现,不过这次可以使用 系结UDT (使用者自订数据型别)和 系结数据行 按钮。
按一下 系结UDT 按钮会显示 系结默认值到使用者自订的数据型别 的对话框,如图16-8所示。这个对话框将显示所有使用者自订数据型别,从清单中选择要关联默认值的使用者自订数据型别。图16-8中,可以看见area_code及brand_type数据型别。如果已经定义了很多使用者自订资料型别,它们也会显示在此清单中。操作完成后,按一下 套用 再按 确定 即可返回 预设属性 窗口。
3. 要将默认值系结到数据行上,按一下 系结数据行 按钮, 系结默认值到数据行 的对话框即会显示。现在选择要系结的数据行。首先从 数据表 下拉式清单中选择数据表名称,然后从 未系结数据行 清单中选择要系结默认值的数据行名称。然后按一下 新增 (图16-9显示从Product_Info数据表中的系结数据行清单新增Price数据行的对话框)。
按一下 确定 返回 预设属性 窗口,然后按一下 确定 关闭 预设属性 窗口。
图16-8 「系结默认值到使用者自订的数据型别」对话框
图16-9 「系结默认值到数据行」对话框
要从使用者自订类型中解除预设对象,可在 预设属性 窗口中开启如上所述的 系结默认值到使用者自订的数据型别 对话框,然后清除 系结 复选框。要解除预设对象的默认值,开启 系结默认值到数据行 对话框,选择数据行名称,按一下 移除 。
要删除预设对象,首先必须先从其它对象中解除预设对象的系结。如果您试图删除与对象系结的预设,SQL Server将传回错误讯息。要删除预设对象,按一下Enterprise Manager左边窗格中的 预设 ,在预设对象名称上按右钮,并在快捷菜单中选择 删除 ,再按一下 卸除对象 对话框中的 卸除全部 。
到此为止,我们已讲述了预设对象,下面将开始介绍条件约束。
条件约束
条件约束用于自动维护数据的完整性。举个例子,您可以将一个整数数据行条件约束在1到100的范围内,那么超出此范围的数值则无法被接受(CHECK功能即可设立此条件约束)。在单一资料行上的条件约束称为资料行条件约束(column constraint),它只约束该数据行的取值范围。影响两个或多个数据行的条件约束称为资料表条件约束(table constraint),它确保数据行中值的结合符合条件约束的要求。条件约束的五种类型为NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY和CHECK。
使用T-SQL建立和修改条件约束
在这部分,我们将学习各种类型的条件约束和如何用T-SQL建立条件约束。稍后的部分将学习用Enterprise Manager完成同样的过程。
NOT NULL
NOT NULL条件约束相当简单。实际上在本章和前面章节的例子中我们已经接触过了,置于数据行中的NOT NULL条件约束能避免在数据行中插入NULL值(这与允许NULL值的NULL条件约束相反)。使用T-SQL修改数据行时,可以在建立数据表时或在建立数据表以后指定该数据行为NOT NULL(详细内容请参阅 第10章 关于修改数据库数据表部分)。
UNIQUE
UNIQUE条件约束用以确保一个或多个数据行中没有重复的数值。换句话说,加强资料行中数值的唯一性。要加强这种唯一性,SQL Server在UNIQUE条件约束中建立一个唯一的非丛集索引。您可以指定索引是丛集还是非丛集的,但要记住的是,一个数据表只允许有一个丛集索引。
________________________________________
说明
本章将经常使用丛集索引和非丛集索引这两个专有名词,如果您对它们的含义不是十分确定, 第17章 将详细介绍这两种类型的索引。
________________________________________
UNIQUE条件约束可以用于任一个非PRIMARY KEY的条件约束(将于下一部分介绍)的资料行,PRIMARY KEY条件约束便加强了值的唯一性。UNIQUE条件约束可以用于允许NULL值的数据行,而PRIMARY KEY条件约束不能。UNIQUE条件约束将忽略NULL值。一个被UNIQUE限制的数据行可以被FOREIGN KEY条件约束引用(在本章后面 〈FOREIGN KEY〉 部分介绍)。一张数据表能有多个UNIQUE条件约束,只要数据表的索引数不超过249个非丛集索引和1个丛集索引。
要用T-SQL为数据表建立UNIQUE条件约束,须执行CREATE TABLE或ALTER TABLE命令。例如,下面的陈述式将建立customer数据表,并在其中的SSN数据行上建立UNIQUE条件约束作为丛集索引:
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11) NOT NULL UNIQUE CLUSTERED,
cust_phone char(10) NULL
)
GO
前面的CREATE陈述式使用了一个数据行条件约束。下面的例子同样将建立customer数据表,而这次在first_name、mid_init和last_name资料行上新增UNIQUE资料表条件约束:
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11) NOT NULL UNIQUE CLUSTERED,
cust_phone char(10) NULL,
CONSTRAINT UQ_full_name UNIQUE NONCLUSTERED (first_name,
mid_init, last_name)
)
GO
UNIQUE数据表条件约束(多于一数据行的条件约束)确保数据行中的所有数值是唯一的。即表示此数据库无法接受first name、mid initial及last name完全相同的客户。注意此处的UNIQUE资料表条件约束是一个非丛集索引,因为在SSN中已经存在一个丛集索引。
要为现存数据表新增UNIQUE条件约束,须使用ALTER TABLE命令。如果要透过新增UNIQUE条件约束来修改已有的数据行,数据表中所有现存的列在这些数据行中必须保持单一或NULL的数值,否则会显示一条错误讯息,提示您不能新增UNIQUE条件约束。假设我们已经建立了没有条件约束的customer数据表。下面是新增数据行条件约束和数据表条件约束的两组命令:
ALTER TABLE customer
ADD CONSTRAINT UQ_ssn UNIQUE CLUSTERED(SSN)
GO
ALTER TABLE customer
ADD CONSTRAINT UQ_full_name UNIQUE NONCLUSTERED (first_name,
mid_init, last_name)
GO
同样的,您只能在现存的资料符合条件约束要求时,为资料表新增条件约束。
要用T-SQL来修改数据行或数据表中已有的UNIQUE条件约束,必须先删除条件约束再重新建立。和默认值一样,为了能够简单地完成查询和删除条件约束,而不用判断SQL Server给它们分配了什么名称,您应使用描述性名称。在 〈使用Enterprise Manager建立和修改条件约束〉 部分,我们将看到,当用Enterprise Manager修改条件约束时,SQL Server将自动删除旧的条件约束,并在储存修改时重新建立条件约束。
主索引键
主索引键条件约束是用于指定数据表中一或多个数据行的 主索引键 (primary key),能唯一的区分某一数据列。由于主索引键的设定是为了辨识数据列,所以主索引键条件约束不可以是NULL;这一点与UNIQUE条件约束恰巧相反。为一组数据行定义主索引键条件约束时,为符合条件约束,数据行中值的结合对于每一数据列都必须是唯一的。和UNIQUE条件约束一样,PRIMARY KEY条件约束不允许有重复的值,并在主索引键中自动建立一个单一的索引。您也可以指定主索引键的索引是丛集还是非丛集;如果没有特别指定,数据表将被自动预设为丛集索引。
每张资料表只有一个PRIMARY KEY条件约束。IDENTITY数据行是做为主索引键的最好选择,或是相对于其它数据列时该数据行(或一组数据行)的值是唯一值,就可以设定主索引键。举例来说,在范例数据表customer中,我们可以将SSN数据行设为主索引键,而不是在数据行中建立UNIQUE条件约束。PRIMARY KEY条件约束不允许NULL值,所以会加强SSN数据行中值的唯一性,并自动在主索引键数据行中建立丛集索引。下面的T-SQL命令示范指定SSN数据行作为主索引键的方法。透过这种方法SQL Server会主动命名此PRIMARY KEY条件约束,因此这并不是最好的方法,因为以后可能需要透过名称来删除该键值(但是您无法知道SQL将此PRIMARY KEY取了什么名称)。
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11) PRIMARY KEY,
cust_phone char(10) NULL
)
GO
另一种可行的方法是以增加CONSTRAINT关键词来命名。使用下面的命令将主索引键命名为PK_SSN:
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11) CONSTRAINT PK_SSN PRIMARY KEY,
cust_phone char(10) NULL
)
GO
您也可以在定义了所有数据表的数据行后,再指定PRIMARY KEY条件约束。数据行名称必须在括号中,并在CONSTRAINT后指定,语法如下所示:
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11),
cust_phone char(10) NULL,
CONSTRAINT PK_SSN PRIMARY KEY (SSN)
)
GO
使用ALTER TABLE命令为没有PRIMARY KEY条件约束的数据表新增PRIMARY KEY条件约束。以下为替customer资料表新增PRIMARY KEY:
ALTER TABLE customer
ADD CONSTRAINT PK_SSN PRIMARY KEY CLUSTERED (SSN)
GO
以上的命令包括了选择性的关键词CLUSTERED,是为了表明:尽管数据表预设为丛集索引,我们仍可在主索引键数据行建立丛集索引。
要删除PRIMARY KEY条件约束,须使用ALTER TABLE命令和DROP CONSTRAINT陈述式。下面为删除SSN数据行的条件约束的命令:
ALTER TABLE customer
DROP CONSTRAINT PK_SSN
GO
您应该特别注意的是,只有在DROP CONSTRAINT的陈述式中,需要条件约束名称。要使用T-SQL命令修改数据表中现存的PRIMARY KEY条件约束,必须先使用ALTER TABLE...DROP CONSTRAINT删除现存条件约束和ALTER TABLE... ADD CONSTRAINT陈述式来新增条件约束以修改资料表。
外部索引键
外部索引键 (FOREIGN KEY)条件约束是用于识别两数据表之间关联性,识别的方式为数据表A外部索引键会参照数据表B中的候选索引键(candidate key,可以是一行或多行)。要将数据列插入一个具外部索引键的数据表中,被插入的资料表会检查参照数据表中的候选索引键,如果两个数据表中的外部索引键和候选索引键的值不符,就不允许插入;反之,就允许插入。
当更新参照数据表中或具外部索引键的数据表的数据列时,也会检查外部索引条件约束,所以在更新候选索引键或外部索引键时,不能违反所设定的条件约束。这个规则有一个例外:更新参照数据表时使用了T-SQL CREATE TABLE陈述式中的ON UPDATE CASCADE选项。这项选择在本章 〈使用Enterprise Manager建立和修改条件约束〉 一节中会介绍。
另外,若是要从参照数据表中删除一个数据列,也会检查外部索引键。如果要删除的数据列有被具外部索引键的数据表引用,就不能被删除。换句话说,每一个在具外部索引键数据表中的数据,在参照数据表中都要有一个相对的数据列,而当所要删除的数据列被另一个数据表所参照时,就不能删除该数据列。这个规则只有一个例外的情形:更新参照数据表时使用了T-SQL CREATE TABLE陈述式中的ON DELETE CASCADE选项。这个选项在 〈使用Enterprise Manager建立和修改条件约束〉 一节中会介绍。
外部索引键数据表只能引用数据表中具PRIMARY KEY条件约束或UNIQUE条件约束的资料行。如果要引用一个不包含上述条件约束的外部索引键,SQL Server会回传错误讯息。外部索引键数据行的数据型别和大小必须和所参照的数据行一致。
请参照以下范例,以便更进一步的了解外部索引键的使用。首先建立一个数据表,命名为items,其中的item_id数据行具主索引键,如下所示:
CREATE TABLE items
(
item_name char(15) NOT NULL,
item_id smallint NOT NULL IDENTITY(1,1),
price smallmoney NULL,
item_desc varchar(30) NOT NULL DEFAULT 'none'
CONSTRAINT PK_item_id PRIMARY KEY (item_id)
)
GO
接下来,我们将建立inventory的数据表,其中有称为FK_item_id的外部索引键,此外部索引键引用items数据表的item_id,如下所示:
CREATE TABLE inventory
(
store_id tinyint NOT NULL,
item_id smallint NOT NULL,
item_quantity tinyint NOT NULL,
CONSTRAINT FK_item_id FORGIEN KEY(item_id)
REFERENCES items(item_id)
)
GO
要观察两个数据表之间的关联性,可参阅图16-10所示的数据库图表(如何建立数据库图表见 第15章 )。本例中,items为具候选索引键item_id的参考数据表。由于它是数据表的主索引键,而数据表中没有其它的UNIQUE条件约束,所以是唯一可能的候选索引键。记住,只有主索引键和UNIQUE条件约束才可能是有效的候选索引键。Inventory数据表的item_id已经被定义了外部索引键,因此建立了两数据表之间的关联性。这两个相关数据行的数据型别都是smallint。在inventory数据表的item_id数据行建立外部索引键,可确保当某个值不存在于items数据表时,就不能插入数据到数据表中,也不能从数据表items中删除被数据表inventory的外部索引键所引用的数据列。换句话说,如果有一项目同时存在于items数据表及inventory数据表,该项目则无法从items数据表或inventory数据表中删除。
图16-10 显示items和inventory数据表间外部索引键关联性的数据库图表
要利用T-SQL命令修改FOREIGN KEY条件约束,必须先删除旧的条件约束,然后使用ALTER TABLE命令建立新的条件约束。这种方法类似于修改PRIMARY KEY条件约束的方法。下面为先删除inventory数据表的旧条件约束,然后新增条件约束的命令:
ALTER TABLE inventory
DROP CONSTRAINT FK_item_id
GO
ALTER TABLE inventory
ADD CONSTRAINT FK_item_id FOREIGN KEY (item_id)
REFERENCES items(item_id)
GO
当您在现存资料行中新增FOREIGN KEY条件约束,SQL Server会检查数据表中现存的数据列,以确保除NULL值外,外部索引键数据行的值符合参照资料表的PRIMARY KEY条件约束或UNIQUE条件约束。当建立FOREIGN KEY条件约束时,可以使用ALTER TABLE的WITH NOCHECK选项,那么SQL Server就不会去验证现有的值,如下所示:
ALTER TABLE inventory
WITH NOCHECK ADD CONSTRAINT FK_item_id
FOREIGN KEY (item_id)
REFERENCES items(item_id)
GO
WITH NOCHECK选项可避免SQL检查数据表中现存列的值。如此,无论现有值为何,都可以新增条件约束到数据表上。新增条件约束后,外部索引键的完整性也会增强。
________________________________________
注意
使用WITH NOCHECK选项时要小心。因为当您预计更新现存数据,但是现存数据中却包含与条件约束冲突的值,您将无法更新现存数据。
________________________________________
您也可以控制是否启用FOREIGN KEY条件约束。如果要插入与现存条件约束冲突的数据列,可以暂时使条件约束无效,等完成插入后再重新使条件约束生效。NOCHECK关键词表示忽略条件约束(条件约束失效);CHECK关键词表示条件约束生效。下面的命令使用NOCHECK和CHECK关键词来控制FOREIGN KEY条件约束是否生效:
ALTER TABLE inventory
NOCHECK CONSTRAINT FK_item_id -- 使条件约束无效
GO
--在此插入您需要的数据列
ALTER TABLE inventory
CHECK CONSTRAINT FK_item_id -- 重新回复条件约束
GO
________________________________________
说明
尽量不要插入与FOREIGN KEY条件约束冲突的资料行。否则可能导致将来数据表的有冲突的数据列无法被更新。
________________________________________
CHECK
CHECK条件约束用于限制数据行中值的允许范围。条件约束中指定的布尔(Boolean)搜寻条件传回的是TRUE时,在数据行中插入或修改的值才算有效。例如,如果我们要限制items数据表的price数据行允许值的可能范围在 $0.01到 $500.00之间,应该使用下面的陈述式:
CREATE TABLE items
(
item_name char(15) NOT NULL,
item_id smallint NOT NULL IDENTITY(1,1),
price smallmoney NULL,
item_desc varchar(30) NOT NULL DEFAULT 'none'
CONSTRAINT PK_item_id PRIMARY KEY (item_id),
CONSTRAINT CK_price CHECK (price >= .01 AND
price <= 500.00)
)
GO
注意,我们在price数据行中允许NULL,且在数据行中有CHECK条件约束。由于SQL Server可以辨别NULL值和其它型别的值,所以尽管有CHECK条件约束,price数据行仍然可允许为NULL值。同时需要注意的是,我们将这个条件约束命名为CK_price。我们之前曾看到,将条件约束命名在稍后即可简单地用T-SQL来删除和重新建立条件约束。例如,把值的范围修改为从 $1.00到 $1000.00之间,可以使用下面的陈述式:
ALTER TABLE items
DROP CONSTRAINT CK_price
GO
ALTER TABLE items
ADD CONSTRAINT CK_price CHECK (price >= 1.00 AND
price <= 1000.00)
GO
第二个ALTER TABLE命令应该与第一次为现存的items数据表新增条件约束时所使用的命令相同。为现存资料表新增CHECK条件约束和新增FOREIGN KEY条件约束所遵守的规则是一样的。所有现存的列将会根据条件约束来检查,如果所有回传的值不是TRUE,则无法将条件约束将新增到数据表中,而且SQL Server将回传错误讯息:指出ALTER TABLE陈述式与CHECK条件约束冲突。如果一定要新增条件约束,使用WITH NOCHECK指定现存的数据列不生效,而将来插入和修改的资料列得以生效。
________________________________________
注意
不建议使用WITH NOCHECK,因为将来可能无法更新不符合条件约束的列。
________________________________________
下面是增加CK_price条件约束时使用WITH NOCHECK的一个例子:
ALTER TABLE items
WITH NOCHECK ADD CONSTRAINT CK_price
CHECK (price >= 1.00 AND price <= 1000.00)
GO
和FOREIGN KEY条件约束一样,在ALTER TABLE中使用CHECK和NOCHECK关键词也可以控制CHECK条件约束是否生效。您可能想用这种方法插入一个超出指定范围但依然有效的价格。下面的例子先停用CK_price条件约束,然后再使其生效:
ALTER TABLE items
NOCHECK CONSTRAINT CK_price -- 使条件约束无效
GO
-- 在此插入资料列
GO
ALTER TABLE items
CHECK CONSTRAINT CK_price -- 重新启用条件约束
GO
________________________________________
说明
只有CHECK和FOREIGN KEY类型的条件约束可以用这种方式来控制是否生效。
________________________________________
用Enterprise Manager建立和修改条件约束
这部分将学习如何用Enterprise Manager设计数据表窗口来建立、修改和删除条件约束,以及在FOREIGN KEY条件约束的情况下,建立数据库图表(在 第15章 介绍了如何建立数据库图表)。使用Enterprise Manager来建立新资料表或编辑现存数据表时,将显示设计数据表窗口。要建立新数据表,在Enterprise Manager的左边窗格中展开服务器和数据库数据夹,在数据表上按右钮,从快捷菜单中选择 新增 / 数据表 。要显示现存数据表的 设计数据表 窗口,首先在左边窗格中找出展开 数据表 ,在右边窗格中的数据表名称上按右钮,然后从快捷菜单中选择 设计数据表 。
允许NULL值
要指定数据行中是否允许NULL值,在 设计数据表 窗口中的 是否允许NULL 标题下简单地选取或清除适当的复选框即可。您可以在建立数据表或修改数据表时设定这一选项。关于允许NULL值的规则请参见 第10章 。图16-11显示了本章前面 〈用T-SQL建立和修改数据表〉 我们曾经建立的customer数据表的 设计数据表 窗口。您可以看到mid_init和cust_phone两个数据行允许NULL值,但其它三数据行不允许NULL值。
图16-11 customer数据表设计数据表窗口的「是否允许NULL」数据行的设定
UNIQUE
1. 要使用Enterprise Manager来建立和修改条件约束,请遵循以下步骤:
在 设计数据表 窗口中,在工具列中选择 数据表索引属性 按钮( 存盘 按钮右边的按钮),在 属性 对话框中选择 索引/索引键 卷标页。图16-12显示了customer数据表的 属性 对话框中的 索引/索引键 卷标页。
使用下面的命令来建立这张数据表。数据表的SSN数据行包括一条作为丛集索引的UNIQUE条件约束(SQL Server自动替索引命名为UQ_customer_398D8EEE;您现在应可明白为条件约束及索引特别命名的好处):
CREATE TABLE customer
(
first_name char(20) NOT NULL,
mid_init char(1) NULL,
last_name char(20) NOT NULL,
SSN char(11) NOT NULL UNIQUE CLUSTERED,
cust_phone char(10) NULL
)
GO
图16-12 customer数据表的属性对话框中的索引/索引键卷标页
2. 要建立一个新的UNIQUE条件约束,在 属性 对话框的 索引/索引键 卷标页上按 新增 按钮,选择条件约束使用的数据行名称,键入新的条件约束名称,然后选择 建立成唯一 - UNIQUE 复选框。如果要使它作为数据行的丛集索引,在数据表中选择 建立成丛集 - CLUSTERED 复选框,并指定填满因子。如果不要SQL Server定期地自动计算索引数据,则选取选取方块旁的选项。
3. 您可以使用 属性 对话框修改UNIQUE条件约束。例如,修改条件约束名称、指定要新增到条件约束的数据行、设定丛集索引选项,以及为索引选择填充因子等。(填满因子将在 第17章 详细介绍。)对条件约束进行修改,完成后按一下 关闭 按钮,然后在Enterprise Manager中按 储存 按钮储存修改。
主索引键
您可以为一或多个数据行指定一个主索引键(PRIMARY KEY)条件约束。按以下步骤指定一个PRIMARY KEY条件约束:
1. 在 设计数据表 窗口中,按一下某列中的储存格来选择某个数据行,或按住CTRL键,按一下数据行名称左侧的灰色方块以同时选择多个数据行。
2. 在所选的一个数据行上按右钮,在快捷菜单中选择 设定主索引键 。设定为主索引键的数据行左边会出现一把小钥匙。在把SSN数据行设定为主索引键后,显示的窗口如图16-13所示。我们也已经删除了SSN数据行的UNIQUE条件约束,因为并不需要在同一数据行同时具有UNIQUE条件约束和PRIMARY KEY条件约束。
图16-13 在设计数据表窗口中设定PRIMARY KEY条件约束
3. 如果要把PRIMARY KEY条件约束移动到另一数据行,只需要把新数据行设定为主索引键即可。您并不一定要先移除原来的主索引键,SQL Server将为您删除和重新建立PRIMARY KEY索引。您也可以在 属性 窗口中修改PRIMARY KEY索引。按一下工具列的 储存 按钮储存操作后,修改就会生效。
________________________________________
说明
如果修改了包含数据的数据表中的PRIMARY KEY条件约束,重新建立索引可能会花费一定时间。若数据表中包含大量数据,欲对索引作较大的修改,例如变更数据行或丛集状态,最好在数据库的非使用高峰期进行这种操作。
________________________________________
外部索引键
要使用Enterprise Manager建立或修改FOREIGN KEY条件约束,可使用 设计数据表 窗口或建立与外部索引键有关联性的数据库图表。最好在建立数据表时(或者至少在数据插入数据表之前)建立外部索引键关联性。下面的例子将解释这个原因。首先,会学习如何使用 设计数据表 来建立FOREIGN KEY条件约束。我们将利用本章前面建立的两个数据库数据表items和inventory来设定外部索引键关键性。我们会重新建立一个有PRIMARY KEY条件约束的item数据表(这是我们之前使用的),只是这次的item_id数据行没有IDENTITY性质。因为我们需要一个item_id已经被更新的范例,而拥有IDENTITY性质的数据行需要较多的步骤才能进行更新。我们也会重新建立一个没有FOREIGN KEY条件约束的inventory数据表,以方便我们稍后加入FOREIGN KEY条件约束。要建立上述的两个数据表,请详以下的陈述式:
CREATE TABLE items
(
item_name char(15) NOT NULL,
item_id smallint NOT NULL,
price smallmoney NULL,
item_desc varchar(30) NOT NULL DEFAULT 'none',
CONSTRAINT PK_item_id PRIMARY KEY (item_id)
)
GO
CREATE TABLE inventory
(
store_id tinyint NOT NULL,
item_id smallint NOT NULL,
item_quantity tinyint NOT NULL
)
GO
要在inventory数据表中增加FOREIGN KEY条件约束,请按照下列步骤:
1. 在Enterprise Manager右方窗口的inventory数据表名称上按右钮,选择 设计数据表 。并在窗口的空白部份按右钮,在快选菜单选取 关联性 进入 关联性 标签页,如图16-14所示:
图16-14 Inventory数据表中属性窗口内的关联性卷标页
2. 按一下 新增 按钮,默认值数据则会显示在窗口内,如图16-15所示。
3. 此范例中,我们在 主索引键表 选取items,并选取item_id数据行作为items及inventory数据表的外部索引键。只要在刚才选取的数据表名称下方空白的数据行部份按一下,即会出现下拉式选项。当选完所要关联的数据表后, 关联性名称 的方块内容就会改变,如图16-16所示。
图16-15 按一下新增之后「关联性」标签页中预设的内容
图16-16 「关联性」卷标页显示items及inventory数据表的外部索引键关联性
4. 下面的窗口下方有几个复选框,范例选项如图16-17所示。若要SQL Server根据外部索引键的关联性一并检查已经存在的数据,须选取 建立时立即检查现有数据 选项。此时数据如果不符,条件约束的建立就会失败。在不需要检查现有资料的情况下,您也可以选择清除此方块。但是若之后要更新或删除已存在的列,就会遇到麻烦。
图16-17 「关联性」卷标页显示已经选取的选项
5. 下一个选项是 复写动作将使用此关联性 。如果不要复写,请勿选择此选项。就算是要复写,其实也不需要选取,因为原数据表中的数据皆根据条件约束检查过,所以复写时,可以不再检视一次。如果仍选择启用,在这两个相关联数据表无法相互配合产生复写数据表的情况下,在复写进行时就会接收到错误讯息,告诉您复写数据列的动作因违反外部索引键条件约束而无法执行。
6. 接下来是 插入和更新动作将使用此关联性 选项。选取此选项表示在插入、更新及删除的动作时,FOREIGN KEY条件约束会同时接受检视。选择后以下的两个复选框就会可以选取。
7. 选择 串联更新相关字段 表示当更新参考数据表中被引用的数据行时(例如:更新items数据表的item_id值),就会一并也更新外部索引键数据表(例如:inventory数据表中的item_id数据行,就会同时被更新-串联更新)。在外部索引键数据表中,除了该数据行外,其余数据行的数据将不会改变。如果您没有选取这个选项,您将会无法更新外部索引键数据表的外部索引键数据行,SQL Server会传送一个如下的错误讯息:「UPDATE陈述式与 'FK_inventory_items' 的COLUMN REFERENCE条件约束互相冲突。此冲突产生在'MyDB'数据库,'inventory' 数据表,'item_id' 资料行。故此陈述式已终止。」
8. 选择 串联删除相关记录 表示在参考数据表中的删除动作一样会删除外部索引键数据表中的数据-串联删除。举个例子,如果删除items数据表中的数据列,那么inventory数据表中拥有相同item_id值的数据列也会同时被删除。这个动作会让您的信息保持一致性。如果您不选取此项目,您就无法更新有被外部索引键数据表引用的数据行。SQL Server会传送一个如下的错误讯息:「DELETE陈述式与 'FK_inventory_items' 的COLUMN REFERENCE条件约束互相冲突。此冲突产生在 'MyDB' 数据库,'inventory' 数据表,'item_id' 资料行。故此陈述式已终止。」
9. 选取完毕后,在 设计数据表 窗口中按一下 关闭 ,然后按一下 储存 钮以储存变更。另一个窗口会显示,告诉您所列示的资料表将会储存到数据库,并显示这两个数据表外部索引键的关联性。完成后,按一下 确定 ,然后在 设计数据表 (非Enterprise Manager窗口,否则Enterprise Manager会关闭)的右上方按一下 关闭 。
另外一个可以建立和修改FOREIGN KEY条件约束的方法是使用数据库图表。要学习如何使用数据库图表来建立和修改FOREIGN KEY条件约束,我们会利用上一个范例所使用的两个数据表: items和inventory数据表,来建立一个图表。首先看一下没有外部索引键关联性的数据库图表,然后再新增外部索引键关联性。初始数据库图表如图16-18所示。
图16-18 包含items和inventory数据表的数据库图表
如图16-18所示,items数据表的item_id数据行是主索引键数据行。它是能用于外部索引键数据表的唯一候选索引键(因为items数据表没有其它的UNIQUE条件约束)。要建立inventory数据表的item_id数据行和items数据表的item_id数据行之间的外部索引键关联性,按下面步骤进行:
1. 按住表示items数据表item_id数据行的列的左边(灰色的方块),将指针拖曳到inventory数据表上(您可以看到指标后面有一条虚线)。当指针指向inventory数据表的item_id列时松开鼠标按钮。此时将显示 建立关联性 对话框,如图16-19。这对话框与之前所示的 设计数据表 窗口的 属性 窗口相类似。对话框中数据表数据行将显示item_id数据行,表示将在两数据表之间的item_id数据行建立外部索引键关联性。
图16-19 「建立关联性」对话框中显示所建议的外部索引键关联性
2. 您可以变更关联性名称,或者视需要选取或清除对话框下面的选项。这些选项在之前已为您介绍。
3. 按一下 确定 以表示外部索引键关联性的两个数据表的图表连接,如图16-20所示(此步骤尚未储存),会有一把小钥匙从外部索引键数据表连接到主索引键数据表。
4. 按一下 储存 按钮储存修改。请输入数据库图表的名称,并确认相关数据表的更改。然后按一下 确定 即完成。
图16-20 显示外部索引键关联性的数据库图表。
要修改现存的外部索引键,可使用此章节介绍的两种方法。在 设计数据表 窗口中,只要再次开启 关联性 标签页进行、储存修改即可。在数据库图表中,则在图表的关联性线条上按右钮,选取 属性 以更新条件约束,或者选取 从数据库删除关联性 完全删除条件约束。然后在依您所需增设一个新的。
CHECK
要使用 设计数据表 窗口建立CHECK条件约束,打开您所要的数据表的 设计数据表 窗口,然后按照以下的步骤执行:
1. 在窗口中按右钮,从快捷菜单中选择 属性 来显示 属性 窗口。按一下 检查条件约束 标签页,按一下 新增 ,如图16-21所示。
2. 接下来输入用于验证插入或修改数据的表达式。在我们的例子中,于items数据表的price数据行新增CHECK条件约束,只有介于 $1.00和 $1000.00之间的值可以被插入到数据表中,如图16-22所示。
3. 注意到三个在下方的选取方块。第一个:选取 建立时立即检查选取数据 选项,表示所有已经存在于数据表的数据皆要经过CHECK条件约束的检视。不符合CHECK条件约束者,则无法建立条件约束。第二个:选取 复写动作必须合乎条件约束 ,表示在复写已经存在的数据时,因为此数据在输入时已检视过,所以复写的数据不需要再检视一次。第三个:选取 插入和更新动作必须合乎条件约束 ,表示要使CHECK条件约束生效。若没有选取此选项,条件约束仍会设立,只是没有设定生效,所以CHECK条件约束不会有作用。
图16-21 「属性」窗口中的「检查条件约束」标签页
图16-22 在items资料表中新增price资料行的CHECK条件约束
若要更改CHECK条件约束,须至 检查条件约束 标签页更新名称、表达式,以及选项。如图16-23显示price数据行的CHECK条件约束从1到1000更新为1到99。
此时您应该可以看见 建立时立即检查现有数据 选项的选取方块已被清除,因为条件约束再之前已经设定了。若要根据变更后的范围来验证现存的资料,则应该选取此选项。若对现有数据的验证失败,则会得到错误讯息,更新的范围则无法成立。您也可以在 选取的条件约束 下拉式清单中选择想要删除的条件约束,只要在 检查条件约束 标签页按一下 删除 按钮来删除条件约束即可。
规则对象
使用CHECK条件约束的另一种方式是建立 规则 对象,用以限制数据行中所插入和修改的数值范围。规则对象类似于预设对象,其与数据表分开建立,而且在删除数据表时也不同时删除规则对象。您必须把规则对象建立系结到数据行上或使用者自订的型别上,本例使用sp_bindrule系统预存程序。和预设对象一样,在SQL Server 2000保留规则对象是为了向后兼容性的缘故。使用CHECK条件约束是条件约束数据行中数值范围的最好办法,但在需要对很多数据行或使用者自订的数据型别应用相同的规则时,规则对象会比较方便。
用T-SQL建立规则对象
例如,让我们建立一个和前面用CHECK条件约束建立的有相同的功能的规则对象。规则使用变量名称 @price来引用items数据表的price数据行。变量名称必须以 @ 符号开始,但是您可以任意选择变量名称。首先我们将建立规则,然后把它系结到数据行上,如下所示:
USE MyDB
GO
CREATE RULE price_rule AS
(@price >= .01 AND @price <= 500.00)
GO
sp_bindrule "price_rule", "items.price", "futureonly"
GO
要解除系结并删除该关联,使用下面的陈述式:
sp_unbindrule "items.price"
GO
DROP RULE price_rule
GO
sp_bindrule和sp_unbindrule的参数与sp_bindefault和sp_unbindefault的参数相同(在本章前面的CREATE DEFAULT和sp_bindefault部分曾介绍过)。尽管您可以在相同的资料行或使用者自订资料型别上同时分配一个规则和一个以上的CHECK条件约束,但是每一个数据行或一个使用者自订型别只能有一个规则。如果您这样做,SQL Server将对插入或修改的数据套用所有的条件约束。
使用Enterprise Manager建立规则对象
依照下列步骤,使用Enterprise Manager建立,并且系结规则对象:
1. 在Enterprise Manager中展开服务器和数据库名称,在 规则 上按右钮,从快捷菜单中选择 新增规则 ,显示 规则属性 对话框。在本例中,我们将规则命名为price_rule,并且新增文字,如图16-24。按一下 确定 完成建立规则对象。
2. 要系结规则,按一下Enterprise Manager左边窗格中的 规则 ,在新规则名称上按右钮,从快捷菜单中选择 属性 显示 规则属性 窗口。和前面系结预设对象一样,按一下 系结UDT 按钮把规则系结到使用者自订数据型别上;或者按一下 系结数据行 按钮把规则系结到数据行上。本例中,按一下 系结数据行 ,选择items数据表的price数据行来系结规则,如图16-25所示。
图16-24 建立规则的「规则属性」窗口
图16-25 系结规则到数据行上
按一下 确定 套用规则,然后再按一下 确定 关闭 规则属性 窗口。
要删除规则,必须先从数据行上或使用者自订数据型别上移除规则。移除规则后,在规则名称上按右钮,从快捷菜单中选择 删除 ,在 卸除对象 对话框中按一下 全部卸除 。如果要删除的规则被系结到任何对象上,SQL Server会出现错误讯息,表示该规则对象不能被删除。
本章总结
本章中,我们学习了可以应用于数据行或数据表的默认值和条件约束的五种类型,以及如何使用T-SQL命令和Enterprise Manager来建立和修改默认值和条件约束。同时也学习了如何使用默认值和规则对象来建立和修改默认值和规则。如果没有分配特定的值,默认值提供了一种为数据行指定默认值的方式。条件约束提供了几种保持数据库中数据完整性的不同方式。如果要在数据库数据表中套用默认值和条件约束,就会发现它们是非常有用的工具。在 第17章 将学习如何使用SQL Server索引,包括丛集索引和非丛集索引,因为索引可以大大提高数据存取的效率。