5 .5 数据库关系图
一旦创建了数据库及其对象,就可以很方便地创建和底层结构链接的实体关系图,这
样,任何必要改动(尤其是创建外键约束)都可以通过一个方便的图形环境应用到数据库中。
SQL Server Management Studio中的数据库关系图就提供了这种功能。但是它不能完全替代
成熟的数据库设计工具。数据库关系图更多地用在数据库部署的测试和开发阶段中。
通 过 SQL Server Management Studio的 “对象资源管理器”中的用户数据库节点可访
问数据库关系图功能。在创建第一个数据库关系图前,需要安装关系图支持对象。方法是
右 击 “数据库关系图”节点并选择“安装关系图支持程序”命令。如果不进行安装,那么
在第一次尝试创建数据库关系图时,系统会弹出一个消息通知缺少“一个或多个支持对象”,
并询问是否要安装它们。安装支持对象或选择“是”会 使 SQL Server创建一个名为 dbo.sysdiagrams的由系统所有的表,它将包括创建的任意关系图的定义。
通过下面的步骤可创建和修改一个数据库关系图:
(1) 展 幵 “数 据 库 ”节 点 ,然 后 展 开 AdventureWorks2008数 据 库 节 点 。右击 AdventureWorkCOOS中 的 “数据库关系图”节点,然后单击“新建数据库关系图”命令。 此时将显示“数据库关系图”窗格,以及一个“添加表”对话框,它按字母顺序列出了数
据库中所有的用户表。
(2) 选择Address(Person)表。单 击 “添加”按钮将Person.Address表添加到关系图中,然
后单击“添加表”对话框上的“关闭”按钮。也可以双击列表中的表将其添加至关系图中。
(3) 右击Address(Person)表,然后单击“添加相关表”命令。这将把所有和Address(Person)
表有关系的表添加到关系图中,如果您不熟悉数据库结构,那么这个功能非常方便。
注意,在关系图中,所有的表都只是互相堆矜在一起的。可以手动重新排列它们,或
者右击关系图的空白处,然后选择 “排列表”命令。SQL Server会把表整齐地排列在窗格 上,使表和它们之间的关系易于査看。
由于关系图中空间有限,可以创建多个关系图把数据库分成功能区域,或者可以显示
关系图上的分页符,把一个大型关系图分成多页。要显示分页符,可右击关系图上的空白
处,然后选择“査看分页符”命令。
右击任何表都可获得改变表在关系图中显示方式的命令、从数据库中删除表的命令、
从关系图中移除表的命令,以及一些通常在“表设计器”工具栏上访问的表修改命令。
5 . 6 视图
SQL Server 2008视图就是保存的命名查询,可以独立于它们引用的表进行管理。视图 和它们所引用的表非常相似,只是它们默认是逻辑对象而非物理对象。但也有例外:当在
视图上创建了一个唯一聚集索引时,该视图就会被“物化”。通常,创建视图是为了抽象复
杂的数据库设计,通过允许访问视图而不是多个表来简化权限,以及安排将数据导出到其
他数据存储器中。
有关视图创建和其他编程对象的内容不在本书讨论范围之内。要了解有关如何和为什么
创建视图的更多信息,请参阅Paul Turley和 Dan Wood编 写 的 《T-SQL编程入门经典(涵盖
SQL Server 2008 & 2005)》一书。有关保护视图的信息,请阅读第6 章。
系统视图
如第4 章所述,系统视图是数据库管理员的系统对象视图。因为有太多的系统视图,
所以这里无法一~描 述 。您可以查阅SQL Server 2008联机从书获取相关信息。系统视图可 分成4 类:
• 信息架构视图—— 信息架构视图是属于INFORMATION_SCHEMA这个特殊架构
的预定义视图。SQL Server 2008实现了 INFORMATION_SCHEMA的 ISO标准定
义,并提供了 SQL Server元数据的一致视图,即它们在版本之间没有改变。 • 目录视图—— 目录视图是从SQL Server中检索元数据的另一种方法。由于目录视 图是最常用的SQL Server元数据界面,因此建议使用该视图而不是信息架构视图。 它们提供了大量可用于排除问题和维护SQL Server 2008的有用信息。如果在固定 脚本巾使用它们,要确保用名称指定列。Microsoft保留了在目录视图末尾添加额外
列的权利,这可能会破坏现有代码。事实上,当在SQL Server 2005和 SQL Server
2008之间选择目录视图时就会发生这种情况。
• 动态管理视图—— 动态管理视图返回用来监视SQL Server进程、诊断问题以及优 化性能的服务器状态信息。第4 章对其做了简要介绍。
• 兼容性目录视图—— 由于 SQL Server 2000中的系统表被弃用,因 此 SQL Server 2008提供了很多和之前的系统表同名的视阁。这些视图仅返冋和SQL Server 2000
兼容的SQL Server 200S功能,并严格规定用于在SQL Server 2000上设计的对象
和脚本。后面的开发工作应使用返回SQL Server 2008特定信息的新目录视图,因 为在未来版本中将删除这些兼容性目录视图。
5 . 7 同义词
所谓同义词,是指给SQL Server架构范围内的数据库对象指定一个名称,数据库应用 程序可使用该名称来代替其由两部分、三部分或四部分组成的名称。例如,如果一个数据
库应用程序引用了另一台服务器上的一个表,它通常需要使用一个由四部分组成的名称。
定义一个同义词实际上就是取一个直接映射到表的别名,而不必对表进行完全限定。下列
代 码 将 在 AdventureWorks2008数据库中创建一个名为Products的同义词,它将引用
AdventureWorksDW2008 数据库中的 dbo.DimProduct 表。
在有了一个新的同义词后,现在打开一个新的査询窗口,然后输入下列代码:
USE AdventureWorks2008 GO
SELECT ProductKey, EnglishProductName, StandardCost FROM dbo.Products
注意,该査询从AdventureWorksDW数据库中返回了 606行,但不需要像下面的示例 这样限定对象名称:
USE AdventureWorks2008 GO
SELECT ProductKey, EnglishProductName, StandardCost FROM AdventureWorksDW2008.dbo.DimProduct
同义词可以用来引用任意数据库或一个链接服务器上的视图、表、存储过程和函数,
从而简化应用程序的数据访问。
5 .8 编程对象
如前所述,有关编程对象创建及其逻辑的内容不在本书的讨论范围之内,但这些对象
的目的和基本用途与这里的讨论还是有关的。数据库管理员需要理解编程对象如何影响数
据库行为。最重要的一个方面通常是安全性,第6 章将会介绍相关内容。
5 . 8 . 1 存储过程
存储过程是存储在服务器的数据库中的T-SQL或托管代码的命名集合。SQL Server存 储过程和其他编程语言中的过程很相似,因为它们都被用来封装重复性任务。存储过程支
持用户声明的变量、条件执行以及许多其他编程功能。
可以使用传统的T-SQL语言,或像C#或 VB.NET等.NET托管语言编写存储过程。
第 14章将讨论使用托管代码创建复杂的存储过程的好处,它们可以突破T-SQL的局限性。
存储过程最主要的用途是封装业务功能,并创建可重用的应用逻辑。由于存储过程存
储在服务器上,因此对业务逻辑的更改可以在一个位置完成。
存储过程还提供对数据库数据的可控修改。通常,给予用户修改数据库表中数据的权
限是一个很糟糕的想法。可以创建仅执行应用程序所需的修改的存储过程。然后可以授予
用户执行存储过程的权限来完成所需的数据修改。
用户创建的存储过程比即席Transact-SQL更有效率,也更安全。它们大大减少了查询和 修改数据库所需的网络数据包数,而为了有效地重用这些存储过程,可以编译并长期缓存它们。
除了用户创建的存储过程之外,SQL Server还提供了数百种系统存储过程。这些系统 存储过程可以用来检索系统信息和修改底层系统对象、它们涵盖了从返回一个所有登录用
户列表的简单存储过程,到创建数据库维护作业的复杂存储过程。后面章节在讨论相关主
题时会涉及其中一些存储过程。
5 .8 .2 函数
SQL Server 2008支持三种类型的用户自定义函数:标量函数、表值函数和聚合函数。 SQL Server函数和其他编程语言中的函数非常相似。它们接受参数,然后基于输入参数执 行操作并返回值。表值函数总是返回table数据类型。标量函数和聚合函数可以返回除text、 ntext和 image之外的任何数据类型。 用户定义函数都可以使用T-SQL或托管代码创建,但聚合函数除外,它总是使用托管
代 码 创 建 。从效率和安全方面来说,用户自定义函数提供了许多和存储过程相同的好处。
它们的区别在于函数不能执行修改数据库状态的代码,而存储过程可以。
在 SQL Server Management Studio的 “对象资源管理器”中,系统函数被分成儿类。
一些函数用来操作用户数据(如聚合函数和字符串函数),而另一些则用来检索系统信息(如
安全性函数和元数据函数)。
5 .8 .3 触发器
触发器是由系统中其他一些动作引发并执行的存储的T-SQL或托管代码对象,它不能
直接执行。SQL Server 2008中有两种触发器:DML触发器和DLL触发器。
1.DML触发器
数据操作语言(Data Manipulation Language, DML)触 发 器 是 由 于 DML命令(INSERT、 UPDATE、DELETE)执行而执行的。SQL Server 2008中 有 两 种 DML触发器:After触发器 和 Instead O f触发器。
After触发器
传统的触发器是After触发器,因为它们是在DML语句在具有已定义的触发器的表上 执 行 “之后”才执行的。触发器中的代码其实也是导致触发器执行的事务的一部分。触发
器主体中的任意ROLLBACK命令都会导致触发器和相关事务回滚。
Instead O f触发器
之所以称为Instead O f触发器,是因为执行的是该触发器中的命令,而不是实际上导 致该触发器执行的事务。Instead O f触发器主要用作将更新发送至包含UNION操作符的视 图中引用的表的方法,因为不能直接更新这些视图。要想了解更多有关Instead Of触发器 和这些分区视图的信息,请 参 阅 Paul Turley和 Dan Wood编 写 的 《T-SQL编程入门经典(涵
盖 SQL Server & 2005)》一书。 2. DDL触发器
数据定义语言(DDL)触发器是由于DDL命令(CREATE、DROP、ALTER)执行而执行的,
其作用域可在数据库或服务器范围。DDL触发器可以审核或防止数据库和服务器修改。
下面的例子演示了如何创建一个数据库级别的DDL触发器,以此审核对数据库做出的修改。
首先创建一个表,记录数据库中发生的所有DDL事件。方法是运行下列脚本:
USE AdventureWorks2008
GO
CREATE TABLE AuditLog ( EventID int IDENTITY (1,1) NOT NULL, LoginName EventTime DDLEvent Eventdata
varchar(75) NOT NULL, datetime NOT NULL, varchar(100) NULL, xml NOT NULL)
GO
接着创建一个触发器,它将在任何DDL级别的事件执行时执行。该触发器使用了一个名
为 EVENTDATA的系统函数,后者返回一个XML结果集,包含有关DDL事件的所有信息。
该触发器使用XQUERY命令将XML数据拆解成关系结果集,然后将其插入到审核表中。
USE AdventureWorks2008
GO
CREATE TRIGGER DatabaseAudit ON DATABASE
FOR DDL_DATABASE一LEVEL_EVENTS
AS
DECLARE @data XML = EVENTDATA() INSERT AuditLog(LoginName, EventTime,DDLEvent,EventData)
VALUES
(SYSTEM_USER
r
GETDATE()
r
@data.value(' (/EVENT_INSTANCE/TSQLCommand) [1] * r ,nvarchar (2000)•) ,@data) RETURN
GO
现在测试该触发器,创建并删除一个名为TriggerTest的表,然后査询审核表看是否捕 获了想要的信息:
USE AdventureWorks2008
GO
CREATE TABLE TriggerTest ( Columnl int ,Column2 int) DROP TABLE TriggerTest SELECT * FROM AuditLog
结果应该是与图5-31类 似 的两行(当然,您 的 LoginName和 EventTime会有所不同)。
注意:
为了确保此触发器不会干扰本书后面的一些练习,可以执行下列命令刪除它。
DROP trigger DatabaseAudit ON DATABASE
5 . 8 . 4 程序集
程序集是包含数据库编程对象的文件,通过使用Visual Studio创建。它们可以包含使 用任何托管语言(如 C#或 VisualBasic.Net)编写的存储过程、函数、触发器、聚合函数和数 据类型。由于集成了公共语言运行时(CLR),所以可在数据库引擎中可以直接访问它们。
在某些特定的情况下,例如需要密集而递归的数学操作或复杂的字符串操作时,托管代码
比传统的T-SQL编程更有优势。第 14章将更详细介绍CLR对象和集成。
从 第 14章可以知道,数据库管理员和开发人员之间关系紧张。通常,这种紧张程度会
因为数据库管理员缺乏编程技能而加剧。随着CLR和数据库引擎集成,数据库管理员了解
编程并与和系统交互的开发人员沟通变得比以往更重要。
通过 Visual Studio、Transact-SQL 或 SQL Server Management Studio 可将 CLR 程序集 导入到数据库巾。这 里 主 要 讨 论 Transact-SQL和 SQL Server Management Studio。为了理解
这些内容,您 需 要 t 传一个文件。第 14章将介绍如何创建这个文件,目前只能想象。 要 使 用 SQL Server Management Studio添 加 新 程 序 集 , 依 次 展 开 “数 据 库 ” | “AdventureWOrks2008” | “可编程性”节点,右 击 “程序 集 ”节点,然 后 单 击 “新建程序 集”命令。
在 “新建程序集”对话框(如图5-32所示)中,浏览至该程序集,指定程序集所有者并
为其设置权限。
权限集定义了授予程序集多少访问权来执行包含的操作。“安全”列表项把程序集限
于当前数据库和连接。“外部访问”列表项使程序集能够与操作系统、网络和文件系统交互。
“无限制”列表项使程序集有“外部访问”的所有权限,并且还可以调用非托管代码。第
6 章和第14章将更详细地讨论程序集权限集。
在将程序集添加到数据库中之后,就可以将链接至此程序集的存储过程、函数、触发
器、类型或聚合函数添加到数据库中(要了解具体过程,可参阅第14章)。
5 .8 .5 类型
类型包括系统数据类型、用户定义数据类型、用户定义表类型、用户定义类型以及数
据库中使用的任意XML架构集合。第4 章介绍了系统数据类型,因此这里只介绍其他类型。
1 .用户定义数据类型
用户定义数据类型是系统类型的别名。这些类型仅存在于创建它们的数据库中。用户
定义数据类型常用于提供一个直观的数据类型名称及维护不同表之间数据类型一致性。
例如,如果我要求5 位不同的数据库开发人员创建一个存储个人信息的表,那我可能
会得到5种不同的解决方案。该表可能包含个人姓、名、地址和电话号码列,但很可能这
5 位不同的数据库开发人员对于任一指定的字段提供出3 种不同的数据类型。例如,一位
开发人员可能使用varchar(13)表示电话号码,认为电话号码应表示为(111)111-1111。另一位 幵发人员可能考虑得更全面,提供了国际代码,因此将电话号码的类型指定为varchar(25)。 为避免后面可能发生的类型冲突,可以指定使用用户定义数据类型。
要以图形化方式创建用户定义数据类型,可在“对象资源管理器”中依次展开“数据
库” | AdventureWorks2008| “可编程性”丨“类型”节点,右 击 “用户定义数据类型”节点, 然后单击“新建用户定义数据类型”命令。
图 5-33展示了在.dbo架构中创建一个基于系统类型char(5)的 ZipCode数据类型。通过 在合适的文本框中进行指定,用户定义数据类型也可以绑定至数据库默认值和规则。默认
值和规则将在本章后面介绍。
用户定义数据类型有一些缺点。例如,它们对数据库应用程序是不透明的。例如,应
用程序程序员将无法在使用ZipCode数据类型的应用层实例化变量。程序员必须知道基类 型是char (5)。除了应用层的可见性之外,用户定义数据类型只存在于创建它们的数据库中。
例如,AdventureWorks2008 数据库中的 ZipCode 数据类型可能与 AdventureWorksDW2008
数据库中的ZipCode数据类型不同。而且,这种数据类型一旦创建就不能更改。换句话说, 如果后面想将ZipCode数据类型改成char(9)来存放“zip+4” 编号形式的邮编,必须删除并 重建它。遗憾的是,要删除它,要求不能在任何地方使用它。
2 .用户定义表类型
SQL Server 2008提供了创建表示表定义的用户定义表类型的功能。可使用用户定义表 类型声明变量或将其用作存储过程和函数的参数,使使用信息集更加容易。要创建用户定
义表类型,使用CREATE TYPE提供表定义。下列代码创建了一个用于表示一组客户的表
结构,然后将它用作一个存储过程的输入参数:
CREATE TYPE Customers AS TABLE ( CustomerName varchar (50), CreditLimit decimal, Address varchar(50), PhoneNumber varchar(10));
GO
DECLARE Scustomers Customers INSERT INTO ^customers(CustomerName, CreditLimit, Addressr PhoneNumber) VALUES (••' 2300.00, •,),
(••, 2300.00, ••),
(•\ 2300.00,',、 " )
GO
EXEC usp_AddCustomers @customers GO
提示:
上面的代码只是作演示之用,不会真正执行,因为Adventure Works数据库中并没有名
为 usp AddCustomers的存储过程.
3 .用户定义类型
用户定义类型(UDT)和用户定义数据类型非常相似,只是它们由托管代码创建,并被
定义在导入到SQL Server数据库的程序集中,UDT可以非常复杂,而且可以定义没有对 应系统类型的自定义数据类型。例如,可以创建一个UDT来定义一个真正存储为数字的
社会安全号码数据类型,但不截断前导零。我们还可以在托管代码中利用正则表达式,以
更容易并更准确地验证社会安全号码。
UDT的其他优势在于它们对应用层是可见的。由于它们定义在程序集中,而程序集可
以在数据库应用程序引用,这样就可以使用本地UDT实例化参数。然而,用户定义类型
并不是完美的,在跨数据库应用程序中,用户定义类型可能会产生问题,因为UDT是特
定于数据库的。不过,如果在每个数据库创建UDT时引用了同样的CLR程序集,这个限
制就会减弱。如前所述,第 14章包含有关CLR程序集和可用它创建的数据库对象(包括
UDT)的更多信息。
5 .8 .6 默认值
可以在数据库级创建一个单独的默认值,然后将它绑定到数据库中的任意表列,而不
是在表列上创建默认约束。默认值已被废弃,所以建议在新的开发工作中不再使用它们。
可以在“对象资源管理器”丨“数据库” | “可编程性”节点下找到默认值,但是必须用T-SQL
创 建 它 们 。下面的例子展示了如何创建一个默认的社会安全号码,然后将其绑定到
dbo.Driver 表的 SocSecNum 列 。
USE AdventureWorks2008 GO
IF EXISTS(SELECT * FROM sys.default_constraints WHERE name = •DF一Driver一SocSecNum1> ALTER TABLE dbo.Driver DROP CONSTRAINT DF_Driver一SocSecNum CREATE DEFAULT dfItSocSecNum AS '000000000'
GO
sp bindefault •dfItSocSecNum*, 1dbo.Driver.SocSecNum1
5 .8 .7 规则
和默认值一样,规则也被弃用了。规则类似于CHECK约束。不过,它是在数据库级
别创建的,然后绑定到匹配指定数据类型的任意列。下面的例子展示了如何创建一条规则,
在基于字符的列上强制数字型数据,以及如何把该规则绑定到SocSecNum列。
USE AdventureWorks2008 GO
CREATE RULE AllNumRule AS @value LIKE 1 [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].
GO
sp_bindrule 'AllNumRule *, * dbo.Driver.SocSecNum *
5 . 9 小结
本章包含大量信息,但仍然有大景内容未能介绍。单 单 SQL Server数据库及其包括的 功能就可以写一本书,但是本书并不是这样一本朽。本章的目的是帮助您了解SQL Server 数据库中提供的对象,以及如何创建和管理它们。后续的章节将从数据库管理员的角度深
入 讨 论 SQL Server 2008其他各个方面。 在 第 6章中,您将学会如何保护SQL Server 2008服务器、数据库和所有组成SQL Server
的相关对象的安全。该章将详细介绍许多新特性(如 SQL Server证书、凭据和加密),以及 核心的安全功能,通过这些内容的学习可确保您的服务器尽可能安全。