610 likes | 860 Views
第 7 章 存储过程和触发器. 7.1 存储过程 7.2 触发器. 7.1.1 存储过程介绍. 在 SQL Server 2005 中,使用 T-SQL 语句编写存储过程。存储过程可以接受输入参数、返回表格或标量结果和消息,调用“数据定义语言( DDL )”和“数据操作语言( DML )”语句,然后返回输出参数。使用存储过程的优点如下: ( 1 )存储过程在服务器端运行,执行速度快。 ( 2 )存储过程执行一次后,就驻留在高速缓冲存储器,在以后的操作中,只需从高速缓冲存储器中调用已编译好的二进制代码执行,提高了系统性能。
E N D
第7章 存储过程和触发器 7.1 存储过程 7.2 触发器
7.1.1 存储过程介绍 在SQL Server 2005中,使用T-SQL语句编写存储过程。存储过程可以接受输入参数、返回表格或标量结果和消息,调用“数据定义语言(DDL)”和“数据操作语言(DML)”语句,然后返回输出参数。使用存储过程的优点如下: (1)存储过程在服务器端运行,执行速度快。 (2)存储过程执行一次后,就驻留在高速缓冲存储器,在以后的操作中,只需从高速缓冲存储器中调用已编译好的二进制代码执行,提高了系统性能。 (3)使用存储过程可以完成所有数据库操作,并可通过编程方式控制对数据库信息访问的权限,确保数据库的安全。 (4)自动完成需要预先执行的任务。存储过程可以在SQL Server启动时自动执行,而不必在系统启动后再进行手工操作,大大方便了用户的使用,可以自动完成一些需要预先执行的任务。
7.1.1 存储过程介绍 在SQL Server 2005 中有下列几种类型存储过程: (1)系统存储过程。系统存储过程是由SQL Server提供的存储过程,可以作为命令执行。系统存储过程定义在系统数据库master中,其前缀是“sp_”. 系统存储过程允许系统管理员执行修改系统表的数据库管理任务,可以在任何一个数据库中执行。SQL Server 2005提供了很多的系统存储过程,通过执行系统存储过程,可以实现一些比较复杂的操作,本书也介绍了其中一些系统存储过程。要了解所有的系统存储过程,请参考SQL Server联机丛书。 (2)扩展存储过程。扩展存储过程是指在SQL Server2005环境之外,使用编程语言(例如C++语言)创建的外部例程形成的动态链接库(DLL)。因为扩展存储过程不易撰写,而且可能会引发安全性问题,所以微软可能会在未来的SQL Server中删除这个功能。
7.1.1 存储过程介绍 (3)用户存储过程。可以使用T-SQL语言编写,也可以使用CLR方式编写。 ①存储过程:存储过程保存T-SQL语句集合,可以接受和返回用户提供的参数。存储过程中可以包含根据客户端应用程序提供的信息,在一个或多个表中插入新行所需的语句。存储过程也可以从数据库向客户端应用程序返回数据。 例如,电子商务Web应用程序可能使用存储过程根据联机用户指定的搜索条件返回有关特定产品的信息。 ②CLR存储过程:CLR存储过程是对Microsoft .NET Framework公共语言运行时(CLR)方法的引用,可以接受和返回用户提供的参数。它们在“.NET Framework 程序集”中是作为类的公共静态方法实现的。简单地说,CLR存储过程就是可以使用Microsoft Visual Studio 2005环境下的语言作为脚本编写的、可以对Microsoft .NET Framework公共语言运行时(CLR)方法进行引用的存储过程。
7.1.1 存储过程介绍 • 创建存储过程 • 语法格式: • create procedure 存储过程名 /*定义过程名*/ • @参数 参数类型 /*定义参数的类型*/ • as • 功能语句 /*执行的操作*/
7.1.1 存储过程介绍 对于存储过程要注意下列几点: (1)用户定义的存储过程只能在当前数据库中创建(临时存储过程除外,临时存储过程总是在系统数据库tempdb中创建)。 (2)成功执行CREATE PROCEDURE语句后,存储过程名称存储在sysobjects系统表中,而CREATE PROCEDURE 语句的文本存储在syscomments中。 (3)自动执行存储过程。SQL Server启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员在master数据库中创建,并在sysadmin固定服务器角色下作为后台过程执行。这些过程不能有任何输入参数。 (4)sql_statement的限制。如下语句必须使用对象的架构名对数据库对象进行限定:CREATE TABLE、ALTER TABLE、DROP TABLE、TRUNCATE TABLE、CREATE INDEX、DROP INDEX、UPDATE STATISTICS及DBCC语句。
7.1.1 存储过程介绍 如下语句不能出现在CREATE PROCEDURE定义中: SET PARSEONLY、SET SHOWPLAN_TEXT、SET SHOWPLAN_XML和SET SHOWPLAN_ALL、CREATE DEFAULT、CREATE SCHEMA、CREATE FUNCTION、ALTER FUNCTION、CREATE PROCEDURE、ALTER PROCEDURE、CREATE TRIGGER、ALTER TRIGGER、CREATE VIEW、ALTER VIEW、USE database_name。 (5)权限。CREATE PROCEDURE的权限默认授予sysadmin固定服务器角色成员、db_owner 和db_ddladmin 固定数据库角色成员。sysadmin 固定服务器角色成员和db_owner 固定数据库角色成员可以将CREATE PROCEDURE权限转让给其他用户。
7.1.1 存储过程介绍 2)存储过程的执行 通过EXEC命令可以执行一个已定义的存储过程。 语法格式: EXECUTE { 返回值 = 存储过程名 @参数 名= 值或变量[ OUTPUT ] | [ DEFAULT ] } [ WITH RECOMPILE ] } 存储过程的执行要注意下列几点: (1)如果存储过程名的前缀为“sp_”,SQL Server会首先在master数据库中寻找符合该名称的系统存储过程。如果没能找到合法的过程名,SQL Server才会寻找架构名称为dbo的存储过程。 (2)执行存储过程时,若语句是批处理中的第一个语句,则不一定要指定EXECUTE关键字。
7.1.2存储过程的创建和执行 一、设计简单的存储过程。 【例7.1】 返回081101号学生的cj情况。该存储过程不使用任何参数。 CREATE PROCEDURE p1 AS SELECT * FROM CJB WHERE xh= '081101‘ 存储过程定义后,执行存储过程student_info: EXECUTE p1 如果该存储过程是批处理中的第一条语句,则可使用:p1
7.1.2存储过程的创建和执行 二、使用带参数的存储过程。 【例7.2】 从PXSCJ数据库的三个表中查询某人指定课程的cj和xf。该存储过程接受与传递参数精确匹配的值。 CREATE PROCEDUREp2 @name char (8), @cname char(16) AS SELECT a.xh, xm, kcm, cj, t.xf FROM XSB a INNER JOIN CJB b ON a.xh= b.xhINNER JOIN KCB t ON b.kch= t.kch WHERE a.xm=@name and t.kcm=@cname
CREATE PROCEDURE p2 @name char (8), @cname char(16) AS SELECT xsb.xh, xm, kcm, cj, kcb.xf FROM XSB,CJB,kcb where xsb.xh = cjb.xh and cjb.kch=kcb.kch and xsb.xm=@name and kcb.kcm=@cname
7.1.2 存储过程的创建和执行 1) 执行存储过程student_info1: EXECUTE p2 '王林', '计算机基础' 2) 执行结果与上面相同: EXECUTE p2 @name='王林', @cname='计算机基础' 3) 或者: DECLARE @proc char(20) SET @proc= 'p2' EXECUTE @proc @name='王林', @cname='计算机基础'
7.1.2 存储过程的创建和执行 三、使用带OUTPUT参数的存储过程。 【例7.3】 创建一个存储过程do_insert,作用是向XSB表中插入一行数据。创建另外一个存储过程do_action,在其中调用第一个存储过程,并根据条件处理该行数据,处理后输出相应的信息。 第一个存储过程: CREATE PROCEDURE p3 AS INSERT INTO XSB VALUES('091201', '陶伟', 1, '1990-03-05', '软件工程',50, NULL);
7.1.2 存储过程的创建和执行 第二个存储过程: CREATE PROCEDURE p4 @X bit, @STR CHAR(8) OUTPUT AS BEGIN EXEC p3 IF @X=0 BEGIN UPDATE XSB SET xm='刘英', xb=0 WHERE xh='091201' SET @STR=‘修改成功‘ –显示一个字符串 END ELSE IF @X=1 BEGIN DELETE FROM XSB WHERE xh='091201' SET @STR='删除成功' END END
7.1.2 存储过程的创建和执行 接下来执行存储过程p4来查看结果: DECLARE @str char(8) EXEC p4 0, @str OUTPUT SELECT @str;
7.1.2 存储过程的创建和执行 四、使用带有通配符参数的存储过程。 【例7.4】 从三个表的连接中返回指定学生的xh、xm、所选kcm称及该课程的cj。该存储过程在参数中使用了模式匹配,如果没有提供参数,则使用预设的默认值。 CREATE PROCEDURE p5 @name varchar(30) = '李%' AS SELECT xsb.xh,xm,kcm,cj FROM XSB,kcb,cjb where xsb.xh=cjb.xh and kcb.kch=cjb.kch and xm LIKE @name 执行存储过程: EXECUTE p5 /*参数使用默认值*/ 或者: EXECUTE p5 '王%' /*传递给@name 实参为'王%'*/
7.1.2 存储过程的创建和执行 五、使用OUTPUT游标参数的存储过程。OUTPUT游标参数用于返回存储过程的局部游标。 【例7.5】 在 XSB表上声明并打开一个游标 CREATE PROCEDURE p6 @st_cursor cursor VARYING OUTPUT AS SET @st_cursor = CURSOR FORWARD_ONLY STATIC FOR SELECT * FROM XSB OPEN @st_cursor
在如下的批处理中,声明一个局部游标变量,执行上述存储过程,并将游标赋值给游标变量,然后通过游标变量读取记录。在如下的批处理中,声明一个局部游标变量,执行上述存储过程,并将游标赋值给游标变量,然后通过游标变量读取记录。 DECLARE @MyCursor cursor EXEC p6 @st_cursor = @MyCursor OUTPUT /*执行存储过程*/ FETCH NEXT FROM @MyCursor WHILE (@@FETCH_STATUS = 0) BEGIN FETCH NEXT FROM @MyCursor END CLOSE @MyCursor DEALLOCATE @MyCursor
7.1.2 存储过程的创建和执行 六、使用WITH ENCRYPTION选项。用于对用户隐藏存储过程的文本。 【例7.6】 创建加密过程,使用sp_helptext 系统存储过程获取关于加密过程的信息,然后尝试直接从syscomments 表中获取关于该过程的信息。 CREATE PROCEDURE p7 WITH ENCRYPTION AS SELECT * FROM XSB 存储过程sp_helptext: 可显示规则、默认值、未加密的存储过程、用户定义函数、触发器或视图的文本。 执行如下语句: EXEC sp_helptext p7 结果集为:“对象'encrypt_this' 的文本已加密”。
7.1.3 存储过程的修改 使用ALTER PROCEDURE命令可修改已存在的存储过程并保留以前赋予的许可。 语法格式: alter procedure 存储过程名 @参数 参数类型 [default | output] as sql语句 【例7.7】 对例7.2中创建的存储过程student_info1进行修改,将第一个参数改成学生的xh。 ALTER PROCEDURE p2 @number char(6),@cname char(16) AS SELECT xh, kcm, cj FROM CJB, KCB WHERE CJB.xh=@number AND KCB.kcm=@cname
7.1.3 存储过程的修改 【例7.8】 创建名为select_students的存储过程,默认情况下,该存储过程可查询所有学生信息,随后授予权限。当该存储过程需更改为能检索计算机zy的学生信息时,用ALTER PROCEDURE重新定义该存储过程。 创建select_students存储过程: CREATE PROCEDURE p8 /*创建存储过程*/ AS SELECT * FROM XSB ORDER BY xh 修改存储过程select_students: ALTER PROCEDURE p8 WITH ENCRYPTION AS SELECT *FROM XSB WHERE zy= '计算机‘ORDER BY xh
7.1.4 存储过程的删除 永久地删除存储过程。在此之前,必须确认该存储过程没有任何依赖关系。 语法格式: DROP PROCEDURE 存储过程1,存储过程2….. 【例7.9】 删除PXSCJ数据库中的student_info1存储过程。 IF EXISTS(SELECT name FROM sysobjects WHERE name='student_info1') DROP PROCEDURE student_info1
7.1.5 界面方式操作存储过程 (1)创建存储过程。例如,如果要通过图形向导方式定义一个存储过程来查询PXSCJ数据库中每个同学各门功课的cj. (2)修改存储过程。选择要修改的存储过程,右击鼠标,在弹出的快捷菜单中选择“修改”菜单项,打开“存储过程脚本编辑”窗口,在该窗口中修改相关的T-SQL语句。修改完成后,执行修改后的脚本,若执行成功则修改了存储过程。 (3)删除存储过程。选择要删除的存储过程,右击鼠标,在弹出的快捷菜单中选择“删除”菜单项,根据提示删除该存储过程。
创建一个 存储过程,要求如下: 1、功能:根据kcm求cj小于多少分的学生记录 2、kcm默认值是‘计算机基础’,分数默认值为60分。 3、可以使用通配符实现模糊查询。 练 习 create procedure p9 @kcm varchar(20)='计算机基础%',@cj int=60 as select kcb.kch,kcm,xh,cj from cjb,kcb where cjb.kch=kcb.kch and kcm like @kcm and cj<@cj execute p9 @cj=70
7.2 触发器 相关概念 语法格式 作用和使用方法
7.2.1 触发器的类型 一、DML触发器。 当数据库中发生数据操纵语言(DML)事件时将调用DML触发器。一般情况下,DML事件包括对表或视图的INSERT语句、UPDATE语句和DELETE语句,因而DML触发器也可分为三种类型:INSERT、UPDATE和DELETE。利用DML触发器可以方便地保持数据库中数据的完整性。 二、DDL触发器。 SQL Server 2005新增的功能。由相应的事件触发,DDL触发器触发的事件是数据定义语句(DDL)语句。主要是以CREATE、ALTER、DROP等关键字开头的语句。作用是执行管理操作,例如审核系统、控制数据库的操作等。通常,DDL触发器主要是用于以下一些操作需求:防止对数据库架构进行某些修改;希望数据库中发生某些变化以利于相应数据库架构中的更改;记录数据库架构中的更改或事件。DDL触发器只在响应由T-SQL语法所指定的DDL事件时才会触发。
触发器:一种特殊的存储过程。 目的:保护数据,使系统的处理任务自动执行 种类:update,insert,delete 作用:当有操作影响到触发器保护的数据时,触发器自动执行。同一个表中可以有多个触发器 用法:在销售系统中,通过更新触发器来检测库存量是否达到需要进货的程度 7.2.2DML 触发器的引入
7.2.2 触发器的引入 2.触发器中使用的临时表 inserted 逻辑表:当向表中插入数据时,INSERT触发器触发执行,新的记录插入到触发器表和inserted表中。 deleted逻辑表:用于保存已从表中删除的记录,当触发一个DELETE触发器时,被删除的记录存放到deleted逻辑表中。 3.使用触发器的限制 (1) CREATE TRIGGER 必须是批处理中的第一条语句,并且只能应用到一个表中。 (2) 触发器只能在当前的数据库中创建。 (3) 在同一CREATE TRIGGER语句中,可为多种操作(如 INSERT 和 UPDATE)定义相同的触发器操作。 (5) 一个表的外键在 DELETE、UPDATE 操作上定义了级联,不能在该表上定义 INSTEAD OF DELETE、INSTEAD OF UPDATE 触发器。
7.2.2 触发器的引入 (7) 在触发器内可以指定任意的 SET 语句,所选择的 SET 选项在触发器执行期间有效,并在触发器执行完后恢复到以前的设置。 (8) 触发器中不允许包含以下 T-SQL 语句: create database 、alter database 、load database 、restore database 、drop database、load log 、restore log 、disk init、disk resize和reconfigure (9) 触发器不能返回任何结果,为了阻止从触发器返回结果,不要在触发器定义中包含 SELECT 语句或变量赋值。
7.2.2 触发器的引入 引入目的: 保证数据一致性 问题1:插入数据时数据不一致 问题2:更新数据时数据不一致 问题3:删除数据时数据不一致
1、实质:一种特殊的存储过程。 2、功能:保护数据,自动执行处理任务。 7.2.2 相关内容回顾 创建 保存 被触发 保护数据 3、语法格式: create trigger 触发器名 on 表/视图 for /after/instead of {insert , delete ,update} as 触发器功能
7.2.3 触发器中使用的特殊表——插入数据 学生 表 Inserted 表 98005 李四5 Deleted 表 98004 李四4 98005 李四5
7.2.3 触发器中使用的特殊表——删除数据 学生 表 Inserted 表 Deleted 表 98005 李四5 98004 李四4 98005 李四5
7.2.3 触发器中使用的特殊表——更新数据 学生 表 Inserted 表 98006 李四6 Deleted 表 98005 李四5 98004 李四4 98005 李四5 98006 李四6
7.2.4 作用一:保证数据一致性(删除) 问题1:删除数据时数据不一致 解决办法:触发器 create trigger t1 on kcb for delete as begin delete from cjb where kch=(select kch from deleted) end
7.2.4 作用二:保证数据一致性(更新) 问题2:更新数据时数据不一致 解决办法:触发器 create trigger t2 on cjb for update as begin if update(kch) update cjb set kch=(select kch from inserted) where kch=(select kch from deleted) end
7.2.4 作用三:保证数据一致性(插入) 问题3:插入数据时数据不一致 × 解决办法1:外码 学生 表 三好学生 表 p p
7.2.4 作用三:保证数据一致性(插入) 问题3:插入数据时数据不一致 解决办法2:触发器 alter trigger t3 on good_stu for insert as begin if exists(select * from xsb where xh= (select xh from inserted)) print '插入成功!' else begin print ‘插入不成功' rollback transaction end end
小 结 作用一:保证数据一致性(删除) 作用二:保证数据一致性(更新) 作用三:保证数据一致性(插入)
练 习 【例7.10】 创建一个表table1,其中只有一列a。在表上创建一个触发器,每次插入操作时,将变量@str的值设为“TRIGGER IS WORKING”并显示。 CREATE TABLE table1(a int) GO CREATE TRIGGER t4 ON table1 AFTER INSERT AS BEGIN DECLARE @str char(50) SET @str='TRIGGER IS WORKING' PRINT @str END 向table1中插入一行数据: INSERT INTO table1 VALUES(10)
练 习 【例7.11】 创建触发器,当向CJB表中插入一个学生的cj时,将XSB表中该学生的zxf加上添加的课程的xf。 CREATE TRIGGER t5 ON CJB for INSERT,update AS BEGIN if update(cj) begin DECLARE @num char(6) declare @kc_num char(3) DECLARE @xf int declare @cj int SELECT @cj=cj,@num=xh,@kc_num=kch from inserted if @cj>60 begin SELECT @xf=xf FROM KCB WHERE kch=@kc_num UPDATE XSB SET zxf=zxf+@xf WHERE xh=@num PRINT '修改成功' end end END
练 习 【例7.12】 创建触发器,当修改XSB表中的xh时,同时也要将CJB表中的xh修改成相应的xh(假设XSB表和CJB表之间没有定义外键约束)。 CREATE TRIGGER t6 ON XSB AFTER UPDATE AS BEGIN DECLARE @old_num char(6), @new_num char(6) SELECT @old_num=xhFROM deleted SELECT @new_num=xhFROM inserted UPDATE CJB SET xh=@new_num WHERE xh=@old_num END 修改XSB表中的一行数据,并查看触发器执行结果: UPDATE XSB SET xh='081120' WHERE xh='081101' SELECT * FROM CJB WHERE xh='081120'
练 习 【例7.13】 在删除XSB表中的一条学生记录时将CJB表中该学生的相应记录也删除。 CREATE TRIGGER t7 ON XSB AFTER DELETE AS BEGIN DELETE FROM CJB WHERE xh IN(SELECT xh FROM deleted) END
练 习 【例7.14】 在KCB表中创建UPDATE和DELETE触发器,当修改或删除KCB表中的kch字段时,同时修改或删除CJB表中的该kch。 CREATE TRIGGER t8 ON KCB AFTER UPDATE, DELETE AS BEGIN IF (UPDATE(kch)) UPDATE CJB SET kch=(SELECT kchFROM inserted) WHERE kch=(SELECT kchFROM deleted) ELSE DELETE FROM CJB WHERE kchIN(SELECT kchFROM deleted) END
练 习 【例7.15】 创建表table2,值包含一列a,在表中创建INSTEAD OF INSERT触发器,当向表中插入记录时显示相应消息。 CREATE TABLE table2(a int) GO CREATE TRIGGER t9 ON table2 INSTEAD OF INSERT AS PRINT 'INSTEAD OF TRIGGER IS WORKING' 向表中插入一行数据: INSERT INTO table2 VALUES(10)
7.3 INSTEAD OF触发器 kcb 表 xsb表 cjb 表 学生选课情况 视图 INSTEAD OF触发器。
7.3 INSTEAD OF触发器 INSTEAD OF触发器的设计 如果视图的数据来自于多个基表,则必须使用INSTEAD OF触发器支持引用表中数据的插入、更新和删除操作。 • 如果视图的列为以下几种情况之一: • (1)基表中的计算列。 • (2)基表中的标识列。 • (3)具有timestamp数据类型的基表列。 • 该视图的INSERT语句必须为这些列指定值,INSTEAD OF触发器在构成将值插入基表的INSERT语句时会忽略指定的值。
原理: instead of 触发器被触发时,不执行触发它的语句,而是执行触发器中的sql语句。
7.3 INSTEAD OF触发器 【例7.16】 在PXSCJ数据库中创建视图stu_view,包含学生xh、zy、kch、cj。该视图依赖于表XSB和CJB,是不可更新视图。可以在视图上创建INSTEAD OF触发器,当向视图中插入数据时分别向表XSB和CJB插入数据,从而实现向视图插入数据的功能。 首先创建视图: CREATE VIEW stu_view AS SELECT XSB.xh, zy, kch, cj FROM XSB, CJB WHERE XSB.xh=CJB.xh
7.3 INSTEAD OF触发器 • 创建INSTEAD OF触发器: CREATE TRIGGER t10 ON stu_view • INSTEAD OF INSERT • AS • BEGIN • DECLARE @XH char(6), @XM char(8),@ZY char(12), @KCH char(3), @CJ int • SET @XM='佚名' • SELECT @XH=xh, @ZY=zy, @KCH=kch, @CJ=cj • FROM inserted • INSERT INTO XSB(xh, xm, zy) VALUES(@XH, @XM, @ZY) • INSERT INTO CJB VALUES(@XH, @KCH, @CJ) • END