µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述...

37
主要内容 1 1 2 2 返回总目录 返回总目录 返回总目录 返回总目录 存储过程概述 创建存储过程 触发器的概念和作用 创建触发器 触发器的应用 触发器的高级应用 查看 修改 删除触发器 在大型数据库系统中 存储过程和触发器具有很重要的作用 论是存储过程还是触发器 都是 SQL 语句和流程控制语句的集合 本质而言 触发器也是一种存储过程 存储过程在运算时生成执行方 所以 以后对其再运行时其执行速度很快 SQL Server 2000 不仅 提供了用户自定义存储过程的功能 而且也提供了许多可作为工具使 用的系统存储过程

Transcript of µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述...

Page 1: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

主要内容

第第第第第第第第1111111122222222章章章章章章章章存存储储过过程程和和触触发发器器

返回总目录返回总目录返回总目录返回总目录

↵ 存储过程概述

↵ 创建存储过程

↵ 触发器的概念和作用

↵ 创建触发器

↵ 触发器的应用

↵ 触发器的高级应用

↵ 查看 修改 删除触发器

在大型数据库系统中 存储过程和触发器具有很重要的作用 无

论是存储过程还是触发器 都是 SQL 语句和流程控制语句的集合 就

本质而言 触发器也是一种存储过程 存储过程在运算时生成执行方

式 所以 以后对其再运行时其执行速度很快 SQL Server 2000 不仅

提供了用户自定义存储过程的功能 而且也提供了许多可作为工具使

用的系统存储过程

Page 2: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

1122..11 存储过程概述

12.1.1 存储过程的概念

存储过程 Stored Procedure 是一组为了完成特定功能的 SQL 语句集 经编译后存

储在数据库中 用户通过指定存储过程的名字并给出参数 如果该存储过程带有参数 来

执行它

在 SQL Server 的系列版本中存储过程分为两类 系统提供的存储过程和用户自定义

存储过程 系统过程主要存储在 master 数据库中并以 sp_为前缀 并且系统存储过程主

要是从系统表中获取信息 从而为系统管理员管理 SQL Server 提供支持 通过系统存储

过程 MS SQL Server 中的许多管理性或信息性的活动 如了解数据库对象 数据库信息

都可以被顺利有效地完成 尽管这些系统存储过程被放在 master 数据库中 但是仍可以

在其它数据库中对其进行调用 在调用时不必在存储过程名前加上数据库名 而且当创建

一个新数据库时 一些系统存储过程会在新数据库中被自动创建 用户自定义存储过程是

由用户创建并能完成某一特定功能 如查询用户所需数据信息 的存储过程 在本章中所

涉及到的存储过程主要是指用户自定义存储过程

12.1.2 存储过程的优点

当利用 MS SQL Server 创建一个应用程序时 Transaction-SQL 是一种主要的编程语

言 若运用 Transaction-SQL 来进行编程 有两种方法 其一是 在本地存储 Transaction-SQL 程序 并创建应用程序向 SQL Server 发送命令来对结果进行处理 其二是 可以把

部分用 Transaction-SQL 编写的程序作为存储过程存储在 SQL Server 中 并创建应用程序

来调用存储过程 对数据结果进行处理 存储过程能够通过接收参数向调用者返回结果集

结果集的格式由调用者确定 返回状态值给调用者 指明调用是成功或是失败 包括针对

数据库的操作语句 并且可以在一个存储过程中调用另一存储过程

我们通常更偏爱于使用第二种方法 即在 SQL Server 中使用存储过程而不是在客户

计算机上调用 Transaction-SQL 编写的一段程序 原因在于存储过程具有以下优点

1 存储过程允许标准组件式编程

存储过程在被创建以后 可以在程序中被多次调用 而不必重新编写该存储过程的 SQL语句 而且数据库专业人员可随时对存储过程进行修改 但对应用程序源代码毫无影响 因

为应用程序源代码只包含存储过程的调用语句 从而极大地提高了程序的可移植性

2 存储过程能够实现较快的执行速度

如果某一操作包含大量的 Transaction-SQL 代码或分别被多次执行 那么存储过程要

比批处理的执行速度快很多 因为存储过程是预编译的 在首次运行一个存储过程时 查

Page 3: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

询优化器对其进行分析 优化 并给出 终被存在系统表中的执行计划 而批处理的 Tran-saction-SQL 语句在每次运行时都要进行编译和优化 因此速度相对要慢一些

3 存储过程能够减少网络流量

对于同一个针对数据数据库对象的操作 如查询 修改 如果这一操作所涉及到的

Transaction-SQL 语句被组织成一存储过程 那么当在客户计算机上调用该存储过程时

网络中传送的只是该调用语句 否则将是多条 SQL 语句 从而大大增加了网络流量 降

低网络负载

4 存储过程可被作为一种安全机制来充分利用

系统管理员通过对执行某一存储过程的权限进行限制 从而能够实现对相应的数据访

问权限的限制 避免非授权用户对数据的访问 保证数据的安全 我们将在 14 章 SQLServer 的用户和安全性管理 中对存储过程的这一应用作更为清晰的介绍������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 存储过程虽然既有参数又有返回值 但是它与函数不同 存储过程的返回值只是指明执行������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������是否成功 并且它不能像函数那样被直接调用 也就是在调用存储过程时 在存储过程名������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������字前一定要有 EXEC 保留字 如何执行存储过程见本章下一节

1122..22 创建存储过程

在 MS SQL Server 2000 中 创建一个存储过程有两种方法 一种是使用 Transaction-SQL命令 Create Procedure 另一种是使用图形化管理工具 Enterprise Manager 用 Transaction-SQL 创建存储过程是一种较为快速的方法 但对于初学者 使用 Enterprise Manager 更易

理解 更为简单

当创建存储过程时 需要确定存储过程的三个组成部分

所有的输入参数以及传给调用者的输出参数

被执行的针对数据库的操作语句 包括调用其它存储过程的语句

返回给调用者的状态值 以指明调用是成功还是失败

12.2.1 使用 Enterprise Manager 创建存储过程

按照下述步骤用 Enterprise Manager 创建一个存储过程

1 启动 Enterprise Manager 登录到要使用的服务器

2 选择要创建存储过程的数据库 在左窗格中单击 Stored Procedure 文件夹 此

时在右窗格中显示该数据库的所有存储过程 如图 12-1 所示

3 右击 Stored Procedure 文件夹 在弹出菜单中选择 New Stored Procedure, 此时打开创建存储过程对话框 如图 12-2 所示

Page 4: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

图12-1 EM 中显示的存储过程的详细信息

图12-2 创建存储过程对话框

4 输入存储过程正文

5 单击 Check Syntax 检查语法是否正确

6 单击 OK 保存

7 在右窗格中 右击该存储过程 在弹出菜单中选择 All task, 选择 ManagePermissions 设置权限 如图 12-3 所示

Page 5: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

图12-3 EM 中显示的设置存储过程权限的对话框

12.2.2 用 CREATE PROCEDURE 命令创建存储过程

通过运用 Create Procedure 命令能够创建存储过程 在创建存储过程之前 应该考虑

到以下几个方面

在一个批处理中 Create Procedure 语句不能与其它 SQL 语句合并在一起

数据库所有者具有默认的创建存储过程的权限 它可把该权限传递给其它的用

存储过程作为数据库对象其命名必须符合命名规则

只能在当前数据库中创建属于当前数据库的存储过程

用 Create Procedure 创建存储过程的语法规则如下

CREATE PROC [ EDURE ] procedure_name [ ; number ] [ { @parameter data_type } [ VARYING ] [ = default ] [ OUTPUT ] ] [ ,...n ][ WITH { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ][ FOR REPLICATION ]AS sql_statement [ ...n ]各参数的含义如下

procedure_name是要创建的存储过程的名字 它后面跟一个可选项 number 它是一个整数 用来区

别一组同名的存储过程 存储过程的命名必须符合命名规则 在一个数据库中或对其所有

者而言 存储过程的名字必须惟一

@parameter

Page 6: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

是存储过程的参数 在 Create Procedure 语句中 可以声明一个或多个参数 当调用

该存储过程时 用户必须给出所有的参数值 除非定义了参数的缺省值 若参数的形式以

@parameter=value 出现 则参数的次序可以不同 否则用户给出的参数值必须与参数列表

中参数的顺序保持一致 若某一参数以@parameter=value 形式给出 那么其它参数也必须

以该形式给出 一个存储过程至多有 1024 个参数

Data_type是参数的数据类型 在存储过程中 所有的数据类型包括 text 和 image 都可被用作参

数 但是 游标 cursor 数据类型只能被用作 OUTPUT 参数 当定义游标数据类型时 也

必须对 VARING 和 OUTPUT 关键字进行定义 对可能是游标型数据类型的 OUTPUT 参

数而言 参数的 大数目没有限制

VARYING指定由 OUTPUT 参数支持的结果集 仅应用于游标型参数

Default是指参数的缺省值 如果定义了缺省值 那么即使不给出参数值 则该存储过程仍能

被调用 缺省值必须是常数 或者是空值

OUTPUT表明该参数是一个返回参数 用 OUTPUT 参数可以向调用者返回信息 Text 类型参

数不能用作 OUTPUT 参数

RECOMPILE指明 SQL Server 并不保存该存储过程的执行计划 该存储过程每执行一次都又要重

新编译

ENCRYPTION表明 SQL Server 加密了 syscomments 表 该表的 text 字段是包含有 Create procedure

语句的存储过程文本 使用该关键字无法通过查看 syscomments 表来查看存储过程内容

FOR REPLICATION选项指明了为复制创建的存储过程不能在订购服务器上执行 只有在创建过滤存储过

程时 仅当进行数据复制时过滤存储过程才被执行 才使用该选项 FOR REPLICATION与 WITH RECOMPILE 选项是互不兼容的

AS指明该存储过程将要执行的动作

Sql_statement是任何数量和类型的包含在存储过程中的 SQL 语句

另外应该指出 一个存储过程的 大尺寸为 128M 用户定义的存储过程必须创建在

当前数据库中

下面将给出几个例子 用来详细介绍如何创建包含有各种保留字的存储过程

例 12-1 该存储过程返回所有作者 以及他们的文章和出版者

use pubs

if exists select name from sysobjects

where name=’author_infor’ and type=’p’

Page 7: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

drop procedure author_infor

go

create procedure author_infor as

select au_lname, au_fname, title, pub_name

from authors a inner join titleauthor ta

on a.au_id=ta.au_id inner join titles t

on t.title_id=ta.title_id inner join publishers p

on t.pub_id=p.pub_id

go

例 12-2 在该存储过程中使用了参数

use pubs

if exists select name from sysobjects

where name=’author_infor and type=’p’

drop procedure author_infor

go

use pubs

go

create procedure author_infor

@lastname varchar 40 , @firstname varchar 20

as

select au_lname,au_fname,title, pub_name

from authors a inner join titleauthor ta

on a.au_id=ta.au_id inner join ttitles t

on t.title_id=ta.title_id inner join publishers p

on t.pub_id=p.pub_id

where au_fname=@firstname and au_lname=@lastname

go

例 12-3 在该存储过程中使用了 OUTPUT 保留字

首先创建存储过程

use pubs

go

if exists select name from sysobjects

where name = 'titles_sum' and type = 'p'

drop procedure titles_sum

go

use pubs

go

Page 8: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

create procedure salequa @stor_id char 4 ,@sum smallint output

as

select ord_num, ord_date, payterms, title_id, qty

from sales

where stor_id = @stor_id

select @sum = sum qty

from sales

where stor_id = @stor_id

go

然后在 Query Analyzer 中调用例 12-3 的存储过程

declare @totalqua smallint

execute salequa '7131',@totalqua output

if @totalqua<=50

select '销售信息'='销售等级为 3 销售量为'+rtrim cast @totalqua as varchar 20

if @totalqua>50 and @totalqua<=100

select '销售信息'='销售等级为 2 销售量为'+rtrim cast @totalqua as varchar 20

if @totalqua>100

select '销售信息'='销售等级为 1 销售量为'+rtrim cast @totalqua as varchar 20

运行结果为

ord_num ord_date payterms title_id qty

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

N914008 1994-09-14 00:00:00.000 Net 30 PS2091 20

N914014 1994-09-14 00:00:00.000 Net 30 MC3021 25

P3087a 1993-05-29 00:00:00.000 Net 60 PS1372 20

P3087a 1993-05-29 00:00:00.000 Net 60 PS2106 25

P3087a 1993-05-29 00:00:00.000 Net 60 PS3333 15

P3087a 1993-05-29 00:00:00.000 Net 60 PS7777 25

6 row s affected

销售信息

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

销售等级为 1 销售量为 130

1 row s affected

1122..33 管理存储过程

12.3.1 查看存储过程

存储过程被创建以后 它的名字存储在系统表 sysobjects 中 它的源代码存放在系统

Page 9: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

表 syscomments 中 可以通过 MS SQL Server 提供的系统存储过程来查看关于用户创建的

存储过程信息

1 通过 Enterprise Manager 管理工具同样可以查看存储过程的源代码

其操作如下

1 启动 Enterprise Manager 登录到要使用的服务器

2 选择要创建存储过程的数据库 在左窗格中单击 Stored Procedure 文件夹 此

时在右窗格中显示该数据库的所有存储过程

3 在右窗格中 右击要查看源代码的存储过程 在弹出的菜单中选择 Properties选项 此时便可看到存储过程的源代码 如图 12-4 所示

图12-4 查看存储过程源代码对话框

2 使用 sp_helptext 存储过程查看存储过程的源代码

其语法格式如下

sp_helptext 存储过程名称存储过程名称存储过程名称存储过程名称

例如要查看数据库 pubs 是否是存储过程 reptq1 的源代码 则执行 sp_helptext reptq1������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������! 如果在创建存储过程时使用了 WITH ENCRYPTION 选项 那么无论是使用 Enterprise������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Manager 还是系统存储过程 sp_helptext 都无法查看到存储过程的源代码

12.3.2 重新命名存储过程

修改存储过程的名字使用系统存储过程 sp_rename 其命令格式为

sp_rename 原存储过程名原存储过程名原存储过程名原存储过程名, 新存储过程名新存储过程名新存储过程名新存储过程名

Page 10: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

例 12-4 将存储过程 reptq1 修改为 newproc 其语句为

sp_rename reptq1, newproc

另外 通过 Enterprise Manager 也可修改存储过程的名字 其操作过程与 WINDOWS下修改文件名字的操作类似 即首先选中需修改名字的存储过程 然后右击鼠标 在弹出

菜单中选取 rename 选项 后输入新存储过程的名字

12.3.3 删除存储过程

删除存储过程使用 drop 命令 drop 命令可将一个或多个存储过程或者存储过程组从

当前数据库中删除 其语法规则为

DROP PROCEDURE {procedure}} [,…n]

例 12-5 如将存储过程 reptq1 从数据库中删除 则执行

drop procedure reptq1

go

12.3.4 执行存储过程

执行已创建的存储过程使用 EXECUTE 命令 其语法如下

[EXECUTE] {[@return_statur=] {procedure_name[;number] | @procedure_name_var} [[@parameter=] {value | @variable [OUTPUT] | [DEFAULT] [,…n] [WITH RECOMPILE]各参数的含义如下

@return_status是可选的整型变量 用来存储存储过程向调用者返回的值

@procedure_name_var是一变量名 用来代表存储过程的名字

其它参数据和保留字的含义与 CREATE PROCEDURE 中介绍的一样

例 12-6 该存储过程被用来将两个字符串连接成一个字符串 并将结果返回

创建存储过程

create procedure strconnect @str1 varchar 20 , @str2 varchar 20 , @connect varchar 40 output

as

select @connect=@str1 + @str2

如果我们提供三个字符串来执行这一存储过程 我们将看不到字符串相加的结果 虽

然 Select 语句用来对 result 变量赋值 但 result 结果并没有显示 再执行以下语句

declare @result varchar 40

execute strconnect 'I am', ' John', ' string'

Page 11: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

select 'The result'=@result

则其运行结果为

The result

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

NULL

1 row s affected

若增加 OUTPUT 保留字到 EXECUTE 语句中便可显示返回参数 result 的值 OUTPUT要求参数值被作为一个变量传送 而不是作为一个常量 下面的例子说明@result 变量来

存放由存储过程 strconnect 通过@connect 返回给调用者的结果值 从而使 SQL Server 能

够显示出存储过程的返回值

例 12-7declare @result varchar 40

execute strconnect 'I am', 'John ', @result output

select 'The result'=@result

运行结果为

The result

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

I am John

1 row s affected

12.3.5 修改存储过程

修改以前用 CREATE PROCEDURE 命令创建的存储过程 并且不改变权限的授予情

况以及不影响任何其它的独立的存储过程或触发器常使用 ALTER PROCEDURE 命令 其

语法规则是

ALTER PROC[EDURE] procedure_name [;number] [ {@parameter data_type } [VARYING] [= default] [OUTPUT]] [,...n][WITH {RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION}][FOR REPLICATION]AS sql_statement [...n]其中各参数和保留字的具体含义请参看 CREATE PROCEDURE 命令

下面将举一个例子 使读者对该命令有更为深刻的理解

例 12-8use pubs

go

if exists select name from sysobjects where name = 'oakland_authors' and type = 'p'

drop procedure oakland_authors

go

Page 12: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

/* 创建一个存储过程 该存储过程获取所有居住在加里福尼亚 奥克兰城的作者的信息 */

use pubs

go

create procedure oakland_authors

as

select au_fname, au_lname, address, city, zip

from pubs..authors

where city = 'oakland'

and state = 'ca'

order by au_lname, au_fname

go

/* 查看该存储过程的源代码 */

select o.id, c.text

from sysobjects o inner join syscomments c on o.id = c.id

where o.type = 'p' and o.name = 'oakland_authors'

/* 将执行该存储过程的权限授予 public 角色 */ 关于角色在 17 章介绍

grant execute on oakland_authors to public

go

/* 下面对该存储过程进行修改 使其能够显示出所有居住在加里福尼亚的作者 而不考虑其它地

区居住的作者 */

alter procedure oakland_authors

with encryption

as

select au_fname, au_lname, address, city, zip

from pubs..authors

where state = 'ca'

order by au_lname, au_fname

go

/* 查看该存储过程的源代码 */

select o.id, c.text

from sysobjects o inner join syscomments c on o.id = c.id

where o.type = 'p' and o.name = 'oakland_authors'

go

将该段代码输入到 SQL Server Query Analyzer 窗口中 运行后结果为

Page 13: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

id text

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

1557580587 create procedure oakland_authors

as

select au_fname, au_lname, address, city, zip

from pubs..authors

where city = 'oakland'

and state = 'ca'

order by au_lname, au_fname

1 row s affected

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

id text

1557580587 ???芹??????负?彣??????????蟸?? 泐摍?賯?鎨???????懡 ??跍旟?迨 輵?椿蚿?閗椌

洿?謋鈲?酄衎战胰嵨?襩??噍???秘???糡?媁???? ????妓??识墥 ? ??? 牙阾喯隶堠?潪?????????国卍

嫟??T 沁??????癦? ??傜貒???芦?簳?????窳遳?????诵? 宅?殴?鞧櫰??? ?漨?窦筘???飔??苜址?蛌??

????技???裗唘??紃��铀????楢? 凂??? ???澵???噉骆盲 ??喺尔??沷鸱??蘩??婨辷?卓??秥蛹??? ??

圱??

1 row s affected������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 由于在 ALERT PROCEDURE 中使用了 WITH ENCTYPTION 保留字 所以在查看修改后������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

的存储过程源代码时看到是一些乱码

1122..44 系统存储过程

系统存储过程就是系统创建的存储过程 目的在于能够方便地从系统表中查询信息或

完成与更新数据库表相关的管理任务或其它的系统管理任务 系统过程以 sp_ 为开头

在 Master 数据库中创建并保存在该数据库中 为数据库管理者所有 一些系统过程只能

由系统管理员使用 而有些系统过程通过授权可以被其它用户所使用

系统存储过程主要包括以下几类 这里主要给出每类系统过程中经常使用的系统过

目录存储过程

sp_column_privileges sp_special_columnssp_columns sp_sproc_columnssp_databases sp_statisticssp_fkeys sp_stored_proceduressp_pkeys sp_table_privilegessp_Server_info sp_tables

复制类存储过程

Page 14: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

sp_addarticle sp_adddistpublishersp_adddistributiondb sp_adddistributorsp_addpublication sp_help_agent_profilesp_addpublication_snapshot sp_help_publication_accesssp_addpublisher70 sp_helparticlesp_addpullsubscription sp_addpullsubscription_agentsp_helpdistpublisher sp_addsubscriber sp_addsubscriptionsp_helpdistributiondb sp_addsubscriber_schedulesp_helpdistributor sp_helppublicationsp_helppullsubscription sp_dropsubscribersp_helpreplicationdboption sp_changedistpublishersp_helpsubscription sp_changedistributiondbsp_changedistributor_password sp_link_publicationsp_refreshsubscriptions sp_droparticle sp_dropdistpublisher sp_dropdistributiondbsp_dropdistributor sp_droppublicationsp_droppullsubscription

安全管理类存储过程

sp_addalias sp_droprolesp_addapprole sp_droprolemembersp_addgroup sp_dropServersp_addlinkedsrvlogin sp_dropsrvrolemembersp_addlogin sp_dropusersp_addremotelogin sp_grantdbaccesssp_addrole sp_grantloginsp_addrolemember sp_helpdbfixedrolesp_addServer sp_helpgroupsp_addsrvrolemember sp_helplinkedsrvloginsp_adduser sp_helploginssp_approlepassword sp_helpntgroupsp_change_users_login sp_helpremoteloginsp_changedbowner sp_helprolesp_changegroup sp_helprolemembersp_changeobjectowner sp_dbfixedrolepermissionsp_helpsrvrole sp_defaultdb sp_helpsrvrolemember sp_dropremoteloginsp_defaultlanguage sp_helpusersp_denylogin sp_passwordsp_dropalias sp_remoteoption

Page 15: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

sp_dropgroup sp_revokeloginsp_droplinkedsrvlogin sp_droplogin

分布式查询存储过程

sp_addlinkedServer sp_indexessp_addlinkedsrvlogin sp_linkedServerssp_catalogs sp_primarykeyssp_foreignkeys在以后的章节中 我们会使用或讲解这些存储过程

1122..55 触发器概述

在上面几节我们介绍了一般意义的存储过程 即用户自定义的存储过程和系统存储过

程 本节将介绍一种特殊的存储过程 即触发器 在余下各节中我们将对触发器的概念

作用以及对其的使用方法作详尽介绍 使读者了解如何定义触发器 创建和使用各种不同

复杂程度的触发器

12.5.1 触发器的概念及作用

触发器是一种特殊类型的存储过程 它不同于我们前面介绍过的存储过程 触发器主

要是通过事件进行触发而被执行的 而存储过程可以通过存储过程名字而被直接调用 当

对某一表进行诸如 UPDATE INSERT DELETE 这些操作时 SQL Server 就会自动执行

触发器所定义的 SQL 语句 从而确保对数据的处理必须符合由这些 SQL 语句所定义的规

触发器的主要作用就是其能够实现由主键和外键所不能保证的复杂的参照完整性和数

据的一致性 除此之外 触发器还有其它许多不同的功能

1 强化约束强化约束强化约束强化约束 Enforce restriction

触发器能够实现比 CHECK 语句更为复杂的约束

2 跟踪变化跟踪变化跟踪变化跟踪变化 Auditing changes

触发器可以侦测数据库内的操作 从而不允许数据库中未经许可的指定更新和变化

3 级联运行级联运行级联运行级联运行 Cascaded operation

触发器可以侦测数据库内的操作 并自动地级联影响整个数据库的各项内容 例如

某个表上的触发器中包含有对另外一个表的数据操作 如删除 更新 插入 而该操作

又导致该表上触发器被触发

Page 16: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

4 存储过程的调用存储过程的调用存储过程的调用存储过程的调用 Stored procedure invocation

为了响应数据库更新 触发器可以调用一个或多个存储过程 甚至可以通过外部过程

的调用而在 DBMS 数据库管理系统 本身之外进行操作

由此可见 触发器可以解决高级形式的业务规则或复杂行为限制以及实现定制记录等

一些方面的问题 例如 触发器能够找出某一表在数据修改前后状态发生的差异 并根据

这种差异执行一定的处理 此外一个表的同一类型 INSERT UPDATE DELETE 的

多个触发器能够对同一种数据操作采取多种不同的处理

总体而言 触发器性能通常比较低 当运行触发器时 系统处理的大部分时间花费在

参照其它表的这一处理上 因为这些表既不在内存中也不在数据库设备上 而删除表和插

入表总是位于内存中 可见触发器所参照的其它表的位置决定了操作要花费的时间长短

12.5.2 触发器的种类

SQL Server 2000 支持两种类型的触发器 AFTER 触发器和 INSTEAD OF 触发器 其

中 AFTER 触发器即为 SQL Server 2000 版本以前所介绍的触发器 该类型触发器要求只

有执行某一操作 INSERT UPDATE DELETE 之后 触发器才被触发 且只能在表

上定义 可以为针对表的同一操作定义多个触发器 对于 AFTER 触发器 可以定义哪一

个触发器被 先触发 哪一个被 后触发 通常使用系统过程 sp_settriggerorder 来完成此

任务

INSTEAD OF 触发器表示并不执行其所定义的操作 INSERT UPDATE DELETE而仅是执行触发器本身 既可在表上定义 INSTEAD OF 触发器 也可以在视图上定义

INSTEAD OF 触发器 但对同一操作只能定义一个 INSTEAD OF 触发器

1122..66 创建触发器

上面介绍了有关触发器的概念 作用和一些基本问题 下面我们将分别介绍在 MS SQLServer 中如何用 SQL Server 管理工具 Enterprise Manager 和 Transaction_SQL 来创建触发

在创建触发器以前必须考虑到以下几个方面

CREATE TRIGGER 语句必须是批处理的第一个语句

表的所有者具有创建触发器的缺省权限 表的所有者不能把该权限传给其它用

触发器是数据库对象 所以其命名必须符合命名规则

尽管在触发器的 SQL 语句中可以参照其它数据库中的对象 但是 触发器只能

创建在当前数据库中

虽然触发器可以参照视图或临时表 但不能在视图或临时表上创建触发器 而只

能在基表或在创建视图的表上创建触发器

一个触发器只能对应一个表 这是由触发器的机制决定的

Page 17: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

尽管 TRUNCATE TABLE 语句如同没有 WHERE 从句的 DELETE 语句 但是由

于 TRUNCATE TABLE 语句没有被记入日志 所以该语句不能触发 DELETE 型

触发器

WRITETEXT 语句不能触发 INSERT 或 UPDATE 型的触发器

当创建一个触发器时 必须指定触发器的名字 在哪一个表上定义触发器 激活触发

器的修改语句 如 INSERT DELETE UPDATE 当然两个或三个不同的修改语句也可

以都触发同一个触发器 如 INSERT 和 UPDATE 语句都能激活同一个触发器

12.6.1 用管理工具 Enterprise Manger 创建触发器

其操作步骤如下

1 启动 Enterprise Manger 登录到指定的服务器上

2 展开数据库 然后展开要在其上创建触发器的表所在的数据库 然后单击该表

3 右击鼠标 在弹出菜单中选择 ALL Tasks, 然后单击 Manage Triggers…4 在名字框中选择 new 在文本框中输入触发器文本 如图 12-5 所示

5 单击 Check Syntax 检查语句是否正确

6 单击 Apply 在 Name 下拉列表中会有新创建的触发器名字

7 单击 OK 关闭窗口 创建成功

图12-5 输入触发器 SQL 语句文本

12.6.2 用 CREATE TRIGGER 命令创建触发器

其语法规则如下

CREATE TRIGGER trigger_nameON { table | view }[ WITH ENCRYPTION ]

输入触发器 SQL

语句的文本

Page 18: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

{ { { FOR | AFTER | INSTEAD OF } { [ DELETE ] [ , ] [ INSERT ] [ , ] [ UPDATE ] } [ WITH APPEND ] [ NOT FOR REPLICATION ] AS sql_statement [ ...n ] } | { FOR | AFTER | INSTEAD OF { [ INSERT ] [ , ] [ UPDATE ] } [ WITH APPEND ] [ NOT FOR REPLICATION ] AS { IF UPDATE column [ { AND | OR } UPDATE column ] [ ...n ] | IF COLUMNS_UPDATED { bitwise_operator }

updated_bitmask { comparison_operator } column_bitmask [ ...n ] } sql_statement [ ...n ] }}各参数的说明如下

trigger_name是用户要创建的触发器的名字 触发器的名字必须符合 MS SQL Server 的命名规则

且其名字在当前数据库中必须是惟一的

Table是与用户创建的触发器相关联的表的名字 并且该表已经存在

WITH ENCRYPTION表示对包含有 CREATE TRIGGER 文本的 syscomments 表进行加密

AFTER表示只有在执行了指定的操作 INSERT DELETE UPDATE 之后触发器才被激活

执行触发器中的 SQL 语句 若使用关键字 FOR 则表示为 AFTER 触发器 且该类型触

发器仅能在表上创建

INSTEAD OF请参看 12.8 INSTEAD OF 触发器

[DELETE] [,] [INSERT] [,] [UPDATE]关键字用来指明哪种数据操作将激活触发器 至少要指明一个选项 在触发器的定义

Page 19: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

中三者的顺序不受限制 且各选项要用逗号隔开

WITH APPEND表明增加另外一个已存在某一类型触发器 只有在兼容性水平 指某一数据库行为与

以前版本的 MS SQL Server 兼容程度 不大于 65 时才使用该选项

NOT FOR REPLICATION表明当复制处理修改与触发器相关联的表时 触发器不能被执行

AS是触发器将要执行的动作

Sql_statement是包含在触发器中的条件语句或处理语句 触发器的条件语句定义了另外的标准来决

定将被执行的 INSERT DELETE UPDATE 语句是否激活触发器

IF UPDATE column用来测定对某一确定列是插入操作还是更新操作 但不与删除操作用在一起

IF COLUMNS_UPDATED仅在 INSERT 和 UPDATE 类型的触发器中使用 用其来检查所涉及的列是被更新还

是被插入

Bitwise_operatorj是在比较中使用的位逻辑运算符

Pdated_bitmask是那些被更新或插入的列的整形位掩码 例如 如果表 T 包括 C1 C2 C3 C4 C5

五列 为了确定是否只有 C2 列被修改 可用 2 来做位掩码 如果想确定是否 C1 C2 C3C4 都被修改 可用 14 来做位掩码

Comparison_operator是一比较操作符 用 = 表示检查在 updated_bitmask 中定义的所有列是否都被更新

用 > 表示检查是否在 updated_bitmask 中定义的某些列被更新

Column_bitmask指那些被检查是否被更新的列的位掩码

例 12-9 在 titles 表上创建一个插入 更新类型的触发器 这个触发器的名称为

trg_id_titles 创建触发器的语句如下

create trigger trg_di_titles

on titles

for delete,update

as sql_statements

return

1122..77 触发器的原理

从以上的介绍中我们可以看出触发器具有强大的功能 那么 MS SQL Server 是如何管

理触发器来完成这些任务呢 下面我们将对其工作原理及实现做较为详细的介绍

Page 20: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

每个触发器有两个特殊的表 插入表和删除表 这两个表是逻辑表 并且这两个表是

由系统管理的 存储在内存中 不是存储在数据库中 因此不允许用户直接对其修改 这

两个表的结构总是与被该触发器作用的表有相同的表结构 这两个表是动态驻留在内存中

的 当触发器工作完成 这两个表也被删除 这两个表主要保存因用户操作而被影响到的

原数据值或新数据值 另外 这两个表是只读的 即用户不能向这两个表写入内容 但可

以引用表中的数据 例如可用如下语句查看 DELETED 表中的信息

select * from deleted

下面详细介绍这两个表的功能

12.7.1 插入表的功能

对一个定义了插入类型触发器的表来讲 一旦对该表执行了插入操作 那么对向该表

插入的所有行来说 都有一个相应的副本存放到插入表中 即插入表就是用来存储向原表

插入的内容

12.7.2 删除表的功能

对一个定义了删除类型触发器的表来讲 一旦对该表执行了删除操作 则将所有的删

除行存放至删除表中 这样做的目的是 一旦触发器遇到了强迫它中止的语句被执行时

删除的那些行可以从删除表中得以恢复

需要强调的是 更新操作包括两个部分 即先将更新的内容去掉 然后将新值插入

因此对一个定义了更新类型触发器的表来讲 当报告会更新操作时 在删除表中存放了旧

值 然后在插入表中存放新值

由于触发器仅当被定义的操作被执行时才被激活 即仅当在执行插入 删除 和更新

操作时 触发器将执行 每条 SQL 语句仅能激活触发器一次 可能存在一条语句影响多

条记录的情况 在这种情况下就需要变量@@rowcount 的值 该变量存储了一条 SQL 语

句执行后所影响的记录数 可以使用该值对触发器的 SQL 语句执行后所影响的记录求合

计值 一般来说 首先要用 IF 语句测试@@rowcount 的值以确定后面的语句是否执行

1122..88 INSTEAD OF 触发器

在本章第五节我们已经指出 SQL Server 2000 支持 AFTER 和 INSTEAD OF 两种类型

的触发器 其中 INSTEAD OF 触发器是 SQL Server 2000 的新添加的功能 AFTER 触发

器等同于以前版本中的触发器 当为表或视图定义了针对某一操作 INSERT DELETEUPDATE 的 INSTEAD OF 类型触发器且执行了相应的操作时 尽管触发器被触发 但

相应的操作并不被执行 而运行的仅是触发器 SQL 语句本身

INSTEAD OF 触发器的主要优点是使不可被修改的视图能够支持修改 其中典型的例

子是分割视图 partitioned view 为了提高查询性能 分割视图通常是一个来自多个表

的结果集 但是也正因此而不支持视图更新 下面的例子说明了如何使用 INSTEAD OF

Page 21: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

触发器来支持对分割视图所引用的基本表的修改

例 12-10 首先创建三个表 salemay salejune 和 salejuly 这三个表分别用来保存五

六 七月的销售量信息

create table salemay

sale_id char 6 not null,

sale_name varchar 20 ,

sale_qua smallint

表 salejune 和表 salejuly 与 salemay 具有相同的数据列

创建分割视图 saleviewcreate view saleview

as

select * from salemay

union all

select * from salejune

union all

select * from salejuly

在视图 saleview 上创建 INSTEAD OF 触发器 saleviewtrcreate trigger saleviewtr on saleview

instead of insert

as

begin

declare @sale_id char 4

select @sale_id=sale_id

from inserted

if substring @sale_id,1,3 ='may'

begin

insert into salemay

select sale_id, sale_name, sale_qua

from inserted

end

if substring @sale_id,1,3 ='jun'

begin

insert into salejune

select sale_id, sale_name, sale_qua

from inserted

end

if substring @sale_id,1,3 ='jul'

begin

insert into salejuly

Page 22: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

select sale_id, sale_name, sale_qua

from inserted

end

end

此时能够成功执行插入语句 insert into saleview values ‘jul001’,’先科 VCD’,200INSTEAD OF 触发器的另外的优点是 通过使用逻辑语句以执行批处理的某一部分而

放弃执行其余部分 比如 可以定义触发器在遇到某一错误时 转而执行触发器的另外部

1122..99 触发器的应用

在以上部分我们讨论了触发器的优缺点 工作原理以及创建触发器的具体方法 接下

来我们将阐述各种不同复杂程度的触发器的应用

12.9.1 插入型触发器的应用

例 12-11 向 pubs 数据库的 employee 表插入新的记录

create trigger employee_insupd

on employee

for insert, update

as

declare @min_lvl tinyint,

@max_lvl tinyint,

@emp_lvl tinyint,

@job_id smallint

select @min_lvl = min_lvl,

@max_lvl = max_lvl,

@emp_lvl = i.job_lvl,

@job_id = i.job_id

from employee e, jobs j, inserted i

where e.emp_id = i.emp_id and i.job_id = j.job_id

if @job_id = 1 and @emp_lvl <> 10

begin

raiserror 'job id 1 expects the default level of 10.',16,1

rollback transaction

end

else

if not @emp_lvl between @min_lvl and @max_lvl

begin

Page 23: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

raiserror 'the level for job_id:%d should be between %d and %d.',

16, 1, @job_id, @min_lvl, @max_lvl

rollback transaction

end

当插入一行新数据时

insert employee emp_id,fname,lname,job_id,job_lvl,pub_id

values 'ugv21716m','ugv','dafe',1,10,1389

由于在我的当前 pubs 数据库 job 表中 job_id 为 1 的记录对应的 min_lvl 值为 11 而

max_lvl 值为 30 所以触发器被触发后返回如下信息

Server: Msg 50000, Level 16, State 1, Line -1074283883

The level for job_id:1 should be between 11 and 30.

12.9.2 删除型触发器的应用

例 12-12 当对定义了删除型触发器的 pub_info 表进行删除操作 首先检查要删除几

行 或删除多行则返回错误信息

create trigger dpub_info

on pub_info for delete

as

if @@rowcount = 0

return

if @@ rowcount > 1

begin

rollback transaction

raiserror ” you can only delete one information at one time”,16,1

end

return

当删除一行时此触发器被触发

delete from pub_info where pub_id='0736'

执行以下语句

select * from pub_info where pub_id=’0736’ 时将输出以下信息

0 row s affected

即该记录已被删除

12.9.3 更新型触发器应用

更新型触发器有两种类型 通常意义上的更新型触发器和用于检查列改变的更新型触

发器 这主要是因为更新操作可以涉及到数据项

通常意义上的更新型触发器

Page 24: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

在前面我们已经提到更新操作包括两个部分 先将需更新的内容从表中删除掉 然后

插入新值 因此 更新型触发器同时涉及到删除表和插入表 下面结合具体例子来对其进

行讨论

例 12-13create trigger unemployee

on employee

for update

as raiserror ‘update has been done successfully’, 16, 10

当执行以下的更新语句时

update employee set fname=’smith’ where emp_id=’PMA42628M’

触发器被触发 输出如下信息

Server: Msg 50000, Level 16, State 10, Procedure uemployee, Line 4

update has been done successfully

当执行

select fname from employee where emp_id=’PMA42628M’ 语句时 输出结果如下

fname

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

smith

1 row s affected

在有些更新中 更新的内容并不是整个记录 而仅仅是一列或几列 这时就要用到用

于检查列改变的更新型触发器 它与通常意义上的触发器不同之处主要表现在它包括以下

保留字

IF UPDATE column [{AND | OR} UPDATE column ] [...n] | IF COLUMNS_UPDATED {bitwise_operator} updated_bitmask { comparison_operator} column_bitmask [...n]

在用 Transaction_SQL 的 CREATE TRIGGER 命令创建触发器那部分我们已经给出上

述保留字的具体含义 下面我们将给出两个例子 这两个例子分别用到了 IF UPDATEcolumn 和 IF COLUMNS_UPDATED例 12-14 使用 IF UPDATE column 保留字 在本例中当更新 title 表中的 title_id

数据项时 titleauthor 表中相应的 title_id 也要进行更新

create trigger utitle1 on titles

for update

as

declare @rows int

select @rows=@@rowcount

Page 25: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

if @rows=0

return

if update title_id

begin

if @rows > 1

begin

raiserror 'update to primary keys of multiple row is not permitted' , 16,10

rollback transaction

return

end

update t set t.title_id=i.title_id

from titleauthor t, insertedi,deleted d

where t.title_id=d.title_id

end

return������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 必须首先删除与表 title 已建立主外键的各关系 上述触发器才能被触发

例 12-15 使用 IF COLUMNS_UPDATED 保留字

首先创建两个表 saledata 表和 audisaleData 表 saledata 表保存某一销售业务的销售

信息 audisaledata 表保存针对 saledata 表某些数据项发生变化的跟踪信息

create table audisaledata

audit_log_id uniqueidentifier default newid ,

audit_log_type char 3 not null,

audi_customer_bankaccountnumber char 10 ,

audi_customer_address varchar 50 ,

audi_customer_name char 11 ,

audi_sale_id int,

audi_sale_name varchar 20 ,

audi_sale_qua smallint,

audi_sale_date datetime default getdate

create table saledata

sale_id int not null,

customer_bankaccountnumber char 10 not null,

customer_address varchar 50 ,

cusomer_name char 11 ,

sale_name varchar 20 ,

sale_qua smallint,

sale_date datetime default getdate

Page 26: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

创建触发器 如果 saledata 表中有关客户的银行账号 地址或客户名称数据项更新时

触发器就会被触发 此时将产生一个跟踪记录 并将该记录插入 audisaledata 表中

create trigger upsaledata

on saledata

for update as

if columns_updated & 14 > 0 /*表示第 2 3 或第 4 列数据项被修改时 将开始执行以

下语句*/

begin

insert into audisaledata

audit_log_type,

audi_customer_bankaccountnumber,

audi_customer_address,

audi_customer_name,

audi_sale_id,

audi_sale_name,

audi_sale_qua,

audi_sale_date

select 'old',

del.customer_bankaccountnumber,

del.customer_address,

del.customer_name,

del.sale_id,

del.sale_name,

del.sale_qua,

del.sale_date

from deleted del

insert into audisaledata

audit_log_type,

audi_customer_bankaccountnumber,

audi_customer_address,

audi_customer_name,

audi_sale_id,

audi_sale_name,

audi_sale_qua,

audi_sale_date

select 'new',

ins.customer_bankaccountnumber,

ins.customer_address,

Page 27: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

ins.customer_name,

ins.sale_id,

ins.sale_name,

ins.sale_qua,

ins.sale_date

from inserted ins

end

插入新的销售业务并不能触发该触发器 如执行以下语句

insert into saledata

values 10001,’1234567890’,’成都市人民北路 22 号’,’祥和商场’,’长虹彩电’ 150,getdate

当把更新销售单号为 10001 的记录的客户账号为 2311748936 时 触发器被触发 并

产生一条跟踪记录

update saledata

set customer_bankaccountnumber='2311748936'

where sale_id=10001

当执行 select * from audisaledata 语句时 有如下输出结果

audit_log_id audit_log_type audi_customer_bankaccountnumber audi_customer_address

audi_customer_name audi_sale_id audi_sale_name audi_sale_qua audi_sale_date

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

EF0A3E00-8382-11D4-AF3A-B450B4234B66 old 1234567890

成都市人民北路 22 号 祥和商场 10001

长虹彩电 150 2000-08-05 23:15:05.643

EF0A3E01-8382-11D4-AF3A-B450B4234B66 new 2311748936

成都市人民北路 22 号 祥和商场 10001

长虹彩电 150 2000-08-05 23:15:05.643

2 row s affected

12.9.4 嵌套触发器

当某一触发器执行时 其能够触发另外一个触发器 这种情况称之为触发器嵌套 在

MS SQL Server 中触发器能够嵌套至 32 层 如果不需要嵌套触发器 可以通过 sp_configure选项来进行设置

在执行过程中 如果一个触发器修改某个表 而这个表已经有其它触发器 这时就要

使用嵌套触发器

例 12-16 在该例中有两个触发器 一个作用于 Sale 表 另一个作用于 Store 表 这

两个触发器的定义如下

/*First trigger deletes stores if the sales are deleted*/

create trigger d_sales

on sales

for delete

Page 28: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

as

/*announce the trigger being executed*/

print’delete trigger on the sales table is executing…’

/*declare a temp var to store the store that is being deleted*/

declare @sstorid char 4 ,

@smsg varchar 40

/*now get the value of the store being deleted*/

select @sstorid = stor_id

from deleted

group by stor_id

/*now delete the store record*/

select @smsg=”deleting store”+@sstorid

print @smsg

delete stores

where stor_id=@sstorid

go

/*second trigger delete discounts if a store is deleted*/

create trigger d_stores

on stores

for delete

as

/*announce the trigger being executed*/

print 'delete trigger on the stores table is executing '

/*declare a temp var to store the store that is being deleted*/

declare @sstorid char 4 ,

@smsg varchar 40

select @sstorid=stor_id

from deleted

group by stor_id

if @@rowcount = 0

begin

print 'no rows affected on the stores table'

return

end

/*now delete the store record*/

select @smsg='deleting discounts for store' + @smsg

print @smsg

delete discounts

where stor_id=@sstorid

Page 29: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

go

当 DELETE 操作在表 Sales 上执行时 一个触发器作用于表 sales 之后 引发作用于 store表上的触发器被触发

所以当执行

delete from sales where stor_id=’6380’ 语句时 输出结果如下

delete trigger on the sales table is executing

deleteing store6380

delete trigger on the stores table is executing

1 row s affected

2 row s affected������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 必须删除与 sales 表已建立的各主外键关系 上面的触发器才能被触发

1122..1100 触发器的高级应用

在触发器的应用中 常会遇到这种情况 即被触发的触发器试图更新与其相关联的原

始的目标表 从而使触发器被无限循环地触发 对于该种情况 不同的数据库产品提供了

不同的解决方案 有些DBMS对一个触发器的执行过程采取的动作强加了限制 有些DBMS提供了内嵌功能 允许一个触发器主体对正在进行的触发器所处的嵌套级别 另一些 DBMS提供了一种系统设置 控制是否允许串联的触发器处理 后一些 DBMS 对可能触发的

嵌套触发器级别的数目进行限制 在 MS SQL Server 中 这种能触发自身的触发器被称为

递归触发器 对它的控制是通过限制可能触发的嵌套触发器级别的数目进行限制的 另外

通过是否允许触发嵌套触发器也能实现对它的控制

在 MS SQL Server 中 除非递归触发器的数据库选项被设置 否则 一个触发器不会

被递归触发 有两个类型的递归触发器

直接递归 即当一个触发器触发时 执行的动作又引起同一个触发器的触发 例

如 某一更新操作引起某一表上的触发器被触发 该触发器又执行更新操作 从

而又触发了该触发器

间接递归 即当一个触发器触发时 执行的动作又引起另外一个表的触发器被触

发 第二个触发器又触发第一个触发器

同时触发器也可能和游标一起使用 从而使其功能大大增强 下面我们将给出一个例

子 在该例子中 我们使用了游标和递归触发器 希望使读者对触发器有更全面的了解

例 12-17 在本例中 只要有新职工记录插入 递归更新触发器就使 NoOfReports 列

立即更新 插入触发器修改

首先将递归触发器选项设置为 TRUE:use pubs

go

execute sp_dboption ' pubs', 'recursive triggers', true

Page 30: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

go

然后创建一个 emp_mgr 表create table emp_mgr

emp char 30 primary key,

mgr char 30 null foreign key references emp_mgr emp ,

noofreports int default 0

go

创建插入型触发器

create trigger emp_mgrins

on emp_mgr

for insert

as

declare @e char 30 , @m char 30

/*定义游标*/

declare c1 cursor for

select emp_mgr.emp

from emp_mgr, inserted

where emp_mgr.emp = inserted.mgr

/*打开游标*/

open c1

/*从游标中读取数据 并存入变量@e 中*/

fetch next from c1 into @e

while @@fetch_status = 0

begin

update emp_mgr

set emp_mgr.noofreports = emp_mgr.noofreports + 1

where emp_mgr.emp = @e

fetch next from c1 into @e

end

/*关闭游标*/

close c1

/*释放游标*/

deallocate c1

create trigger emp_mgrupd on emp_mgr

for update

as

if update mgr

begin

Page 31: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

update emp_mgr

set emp_mgr.noofreports = emp_mgr.noofreports + 1

ment mgr's

from inserted

where emp_mgr.emp = inserted.mgr

update emp_mgr

set emp_mgr.noofreports = emp_mgr.noofreports – 1

from deleted

where emp_mgr.emp = deleted.mgr

end

go

插入几行数据

insert emp_mgr emp, mgr values 'harry', null

insert emp_mgr emp, mgr values 'alice', 'harry'

insert emp_mgr emp, mgr values 'paul', 'alice'

insert emp_mgr emp, mgr values 'joe', 'alice'

insert emp_mgr emp, mgr values 'dave', 'joe'

go

该语句将 dave's 的经理由 joe 改为 harryupdate emp_mgr set mgr = 'harry'

where emp = 'dave'

go

select * from emp_mgr

go

修改前该表的信息为

emp mgr NoOfReports

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

Alice Harry 2

Dave Joe 0

Harry NULL 1

Joe Alice 1

Paul Alice 0

5 row s affected

修改后该表的信息为

emp mgr NoOfReports

Page 32: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

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

Alice Harry 2

Dave Harry 0

Harry NULL 2

Joe Alice 0

Paul Alice 0

5 row s affected

在前面我们已经指出 触发器 为突出的作用就是它能实现由主外键不能实现的复杂

的完整性控制 下面的例子就是增强了复杂限制的触发器

例 12-18create trigger u_roysched on roysched

for update

as

declare @rows int

select rows = @@rowcount

if @rows = 0

return

if @rows > 1

begin

rollback tran

raiserror ‘ can only update or add one title at a time.’,16,10

return

end

if select inserted.lorange from inserted < 5

begin

rollback tran

raiserror ‘ can only update lorange above 5’,16,10

return

end

if select inserted.hirange from inserted > 1000

begin

rollback tran

raiserror ‘ can only update hirange below 1000’,16,10

return

end

if select inserted.royalty from inserted <= 1000

begin

rollback tran

Page 33: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

raiserror ‘ can only update royalty above 0’,16,10

return

end

return

当执行如下语句时

update roysched

set lorange=3

where title_id='BU1032'

输出信息为

Server: Msg 50000, Level 16, State 10, Line -1074283883

can only update or add one title at a time.

1122..1111 管理触发器

如果要显示作用于表上的触发器究竟对表有哪些操作 必须查看触发器信息 在 MSSQL Server 中 有多种方法查看触发器信息 在本节我们将介绍两种常用的方法 即通

过 MS SQL Server 的管理工具 Enterprise Manager 以及系统存储过程 sp_help sp_helptext和 sp_depends

12.11.1 使用 Enterprise Manager 显示触发器信息

使用 Enterprise Manager 显示触发器信息 其操作步骤如下

1 运行 Enterprise Manager 登录到指定的服务器

2 选择数据库和表 如图 12-6 所示

Page 34: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

图12-6 表加亮显示后 也可单击右键从弹出菜单中选择 All tasks manage trigger 完成

3 从 Action 菜单项中选择 ALL Tasks 再选择 Manage Triggers 如图 12-7

图12-7 Trigger Properties 对话框 可以查看 修改触发器

12.11.2 使用系统存储过程查看触发器

系统存储过程 sp_help sp_helptext 和 sp_depends 分别提供有关触发器的不同信息

下面我们将分别对其进行介绍

1 sp_help

使用 sp_help 系统过程的命令格式是

sp_help ‘触发器名字触发器名字触发器名字触发器名字’通过该系统过程 可以了解触发器的一般信息 如触发器的名字 属性 类型 创建

时间

例 12-19 执行以下命令

sp_ help dauthors

输出结果为

Name Owner Type Created_datetime

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

dauthors dbo trigger 2000-07-14 11:37:17.970

2 sp_helptext

通过 sp_helptext 能够查看触发器的正文信息 其语法格式为

sp_helptext ‘触发器名触发器名触发器名触发器名’

Page 35: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

例 12-20 执行以下命令

sp_helptext dauthors输出结果为

create trigger dauthors

on authors for delete

as

if @@rowcount=0

return

if @@rowcount>1

begin

rollback transaction

raiserror 'you can only delelte one author at one time',16, 1

end

return

3 sp_depends

通过 sp_depends 能够查看指定触发器所引用的表或指定的表涉及到的所有触发器 其

语法形式如下

sp_depends ‘触发器名字触发器名字触发器名字触发器名字’sp_depends ‘表名表名表名表名’

������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������! 用户必须在当前数据库中查看触发器的信息 而且被查看的触发器必须已经被创建

12.11.3 修改 删除触发器

通过 Enterprise Manager 和系统过程或 Transaction_SQL 命令 可以修改触发器的名字

和正文

1 使用 sp_rename 命令修改触发器的名字

其语法格式为

sp_rename oldname,newname

2 通过 Enterprise Manager 修改触发器正文的操作步骤

通过 Enterprise Manager 修改触发器正文的操作步骤与查看触发器信息一样 修改完

触发器后要使用 Check Syntax 选项对语句进行检查

Page 36: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

3 通过 Alert trigger 命令修改触发器正文

其语法格式为

ALTER TRIGGER trigger_nameON table | view [ WITH ENCRYPTION ]{ { FOR | AFTER | INSTEAD OF { [ DELETE ] [ , ] [ INSERT ] [ , ]

[ UPDATE ] } [ NOT FOR REPLICATION ] AS sql_statement [ ...n ] } | { FOR | AFTER | INSTEAD OF { [ INSERT ] [ , ] [ UPDATE ] } [ NOT FOR REPLICATION ] AS { IF UPDATE column [ { AND | OR } UPDATE column ] [ ...n ] | IF COLUMNS_UPDATED { bitwise_operator }updated_bitmask { comparison_operator } column_bitmask [ ...n ] } sql_statement [ ...n ] }}其中各参数或保留字的含义参看创建触发器一节

4 删除触发器

用户在使用完触发器后可以将其删除 只有触发器属主才有权删除触发器 删除已创

建的触发器有两种方法

用系统命令 DROP TRIGGER 删除指定的触发器 其语法形式如下

DROP TRIGGER 触发器名字触发器名字触发器名字触发器名字

删除触发器所在的表时 MS SQL Server 将自动删除与该表相关的触发器

1122..1122 本章小结

本章着重介绍了 MS SQL Server 中的两个重要概念 存储过程和触发器 我们指出存

储过程 触发器是一组 SQL 语句集 触发器就其本质而言是一种特殊的存储过程 存储

过程和触发器在数据库开发过程中 在对数据库的维护和管理等任务中以及在维护数据库

参照完整性等方面具有不可替代的作用 因此无论对于开发人员 还是对于数据库管理人

Page 37: µÚ12ÕÂ - read.pudn.comread.pudn.com/downloads159/ebook/715821/12.pdf12.1 存储过程概述 12.1.1 存储过程的概念 存储过程 Stored Procedure是一组为了完成特定功能的SQL

员来说 熟练地使用存储过程 尤其是系统存储过程 深刻地理解有关存储过程和触发器

的各个方面问题是极为必要的

在本章中 我们通过较多详尽的实例 全面而又透彻地展示了有关存储过程和触发器

的各种问题 具体来说主要包括以下几个方面

存储过程 触发器的概念 作用和优点

创建 删除 查看 修改存储过程 触发器的方法

存储过程 触发器的各种不同复杂程度的应用

创建 使用存储过程和触发器的过程中应注意的若干问题