《第12章触发器优秀课件.ppt》由会员分享,可在线阅读,更多相关《第12章触发器优秀课件.ppt(40页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第12章触发器第1页,本讲稿共40页12.1 概述 12.1.1 触发器的概念及分类触发器的概念及分类 触发器是一种特殊类型的存储过程,它不同于前面介绍过的一般的存储过程。一般的存储过程通过存储过程名称被直接调用,而触发器主要是通过事件进行触发而被执行 触发器是一个功能强大的工具,它与表格紧密相连,在表中数据发生变化时自动强制执行。触发器可以用于SQL Server约束、默认值和规则的完整性检查,还可以完成难以用普通约束实现的复杂功能。2第2页,本讲稿共40页触发器(Trigger)是一种实施复杂数据完整性的特殊存储过程.在对表或视图执行 UPDATE、INSERT 或 DELETE 语句时自
2、动触发执行自动触发执行,以防止对数据进行不正确、未授权或不一致的修改。触发器是与表紧密联系在一起的,是在特定表上进行定义的,这个特定表也被称为触发器表。触发器和一般的存储过程又有一些不同,它不可以像调用存储过程一样由用户直接调用执行。触发器与表是密不可分的,触发器是不能离开表而独立存在的,触发器主要用于保护表中的数据,实现数据的完整性。对表中数据的操作有三种基本类型,数据插入、修改、删除,因此,触发触发器也有三种类型:器也有三种类型:INSERT、UPDATE、DELETE。当向触发器表中插入数据时,如果该触发器表有INSERT类型的触发器,INSERT触发器就被触发执行。同样的道理,UPDA
3、TE触发器会被数据更新触发执行、DELETE触发器会被数据删除触发执行。3第3页,本讲稿共40页12.1.2 触发器的工作原理触发器的工作原理SQL Server为执行的触发器创建一个或两个专用的临时表:inserted表或者deleted表。inserted表和deleted表的结构总是与被该触发器作用的表的结构相同,而且只能由创建它们的触发器引用。它们是临时的逻辑表,由系统来维护,不允许用户直接对它们进行修改。它们存放于内存中,并不存放在数据库中。触发器工作完成后,与该触发器相关的这两个表也会被删除。1.INSERT触发器的工作原理触发器的工作原理当一个记录插入到表中时,INSERT触发器
4、自动触发执行,相应的插入触发器创建一个inserted表,新的记录被增加到该触发器表和inserted表中。它允许用户参考初始的INSERT语句中的数据,触发器可以检查inserted表,以确定该触发器里的操作是否应该执行和如何执行。4第4页,本讲稿共40页2.DELETE触发器的工作原理触发器的工作原理当从表中删除一条记录时,DELETE触发器自动触发执行,相应的删除触发器创建一个deleted表,deleted表是个逻辑表,用于保存已经从表中删除的记录,该deleted表允许用户参考原来的DELETE语句删除的已经记录在日志中的数据。应该注意:当被删除的记录放在deleted表中的时候,该
5、记录就不会存在于数据库的表中了。因此,deleted表和数据库表之间没有共同的记录。3.UPDATE触发器的工作原理触发器的工作原理修改一条记录就等于插入一条新记录,删除一条旧记录。进行数据更新也可以看成由删除一条旧记录的DELETE语句和插入一条新记录的INSERT语句组成。当在某一个触发器表的上面修改一条记录时,UPDATE触发器自动触发执行,相应的更新触发器创建一个deleted表和inserted表,表中原来的记录移动到deleted表中,修改过的记录插入到了inserted表中。本章首页本章首页本章首页本章首页5第5页,本讲稿共40页12.2 触发器的创建12.2.1 使用使用T-S
6、QL语句创建触发器语句创建触发器1.创建触发器的创建触发器的SQL语句语法:语句语法:创建触发器的一般语法如下。CREATE TRIGGER trigger_name ON table_name WITH ENCRYPTION FOR DELETE,INSERT,UPDATEASsql_statement trigger_name:要创建的触发器名称。触发器名称必须符合标识符规则,并且在数据库中必须唯一。table_name:指定所创建的触发器与之相关联的表名。必须是一个现存的表。6第6页,本讲稿共40页 WITH ENCRYPTION:加密创建触发器的文本。FOR INSERT,DELETE
7、,UPDATE:指定所创建的触发器将在发生哪些事件时被触发,也即指定创建触发器的类型。“INSERT”,表示创建插入触发器;“DELETE”,表示创建删除触发器;“UPDATE”表示创建更新触发器。必须至少指定一个选项。在触发器定义中允许使用以任意顺序组合的这些关键字。如果指定的选项多于一个,以逗号分隔这些选项。sql_statement:指定触发器执行的SQL语句。触发器只能在当前数据库中创建,并且一个触发器只能作用在一个表上。在同一条 CREATE TRIGGER 语句中,可以为多种用户操作(如 INSERT 和 UPDATE)定义相同的触发器操作。值得注意的是,在SQL Server 2
8、000中也可以对视图建立触发器,只要将视图名称作为table_name用在创建语法中就可以了。但是,对视图建立触发器有一些限制,详细信息请参考SQL Server 2000联机丛书。7第7页,本讲稿共40页2.创建创建INSERT触发器触发器下面以为表student建立一个插入触发器为例,介绍创建INSERT触发器的方法。当某个班级增加一名学生,即向表student中插入一行数据时,需要更改该学生所在班级的记录,以增加该班级的学生总人数。下例使用INSERT触发器自动完成这个工作。【例例12-1】为student表建立INSERT触发器以自动更新class表学生人数。USE jwglGO/*如
9、果存在同名的触发器,则删除之*/IF EXISTS(SELECT name FROM sysobjects WHERE type =TR AND name =student_insert)DROP TRIGGER student_insertGO 8第8页,本讲稿共40页CREATE TRIGGER student_insert ON student FOR INSERTASDECLARE NumOfStudent TINYINTSELECT NumOfStudent=c.student_num FROM class c,inserted i WHERE c.class_id=i.class_
10、idIF (NumOfStudent 0)BEGIN UPDATE class SET student_num=student_num+1 FROM class c,inserted i WHERE c.class_id=i.class_id ENDELSE 9第9页,本讲稿共40页BEGIN UPDATE class SET student_num=(SELECT COUNT(s.student_id)FROM student s,inserted i WHERE s.class_id=i.class_id)FROM class c,inserted i WHERE c.class_id=i
11、.class_id ENDGO下面来测试它的运行情况。1.首先查询一个班级的当前人数首先查询一个班级的当前人数,如“g99403”。执行如下代码:SELECT*FROM class WHERE class_id=g99403系统显示如下运行结果:class_id monitor classroom student_num g99403 成佳洱 教学楼212 510第10页,本讲稿共40页从上面执行结果可以看见,当前g99403班级当前的学生人数是5人。2.现在,使用上一章建立的添加学生记录的存储过程现在,使用上一章建立的添加学生记录的存储过程spAddStudent添加一个名字为程涛的学生记录
12、添加一个名字为程涛的学生记录。执行如下代码:EXEC spAddStudent g9940306,程涛,男,1981-9-22,g99403,1999-9-1,南京市御道街2号3.再一次使用前面的语句查询再一次使用前面的语句查询g99403班级的信息,可以看到下面班级的信息,可以看到下面的结果显示的结果显示:class_id monitor classroom student_num g99403 成佳洱 教学楼212 6上面执行结果显示,class表中该班级记录的student_num字段已经自动更新为6了。11第11页,本讲稿共40页class表表student_num列自动更新的原因是列
13、自动更新的原因是:在student表上执行了INSERT操作后,触发了插入触发器student_insert,该触发器自动对学生人数进行累加(或重新统计)。从上述例子可以看出,通过触发器可以维护数据完整性。在上述定义插入触发器时,使用了inserted专用临时表,它保存所插入行的一个拷贝。下面我们来具体看看上面例子完整的执行过程。通过存储过程spAddStudent,系统对student表进行了INSERT操作,执行了插入一行数据的操作。系统检查被插入新值的正确性(如:约束等),如果正确,则将新行插入到student表,同时建立临时表inserted并在这个表中也插入新行。12第12页,本讲稿
14、共40页 执行插入触发器中的语句。首先定义了一个变量NumOfStudent来检查class表中对应班级的学生人数,如果学生人数为0(这种情况可能发生在新添加一个班级等)则重新统计该班级的学生人数,否则直接把该班级的学生人数加1(当然也可以不用判断,而在每次触发时都重新统计学生人数)。如果整个过程中某个环节出现错误,或执行到ROLLBACK语句,系统将回滚整个操作,包括对student表学生记录的插入和对class表student_num的修改。从事务角度来说,触发器与触发它的语句(如:INSERT语句)可看作同一个事务的不同部分。在执行了插入操作后我们看到结果显示了两次“(所影响的行数为 1
15、 行)”的提示。第一次表示插入操作成功,第二次表示由插入数据操作引发的执行INSERT触发器操作对student_num列修改成功。13第13页,本讲稿共40页3.创建创建DELETE触发器触发器当从某个班级删除一名学生,即从表student中删除一行数据时,需要更改该学生所在班级的学生总人数。对student_insert 的代码稍加修改就可以得到能自动完成这个工作的删除触发器。【例例12-2】为student表建立DELETE触发器,在删除学生记录时自动更新class表中相应班级的学生人数。USE jwglGO/*如果存在同名的触发器,则删除之*/IF EXISTS(SELECT name
16、 FROM sysobjectsWHERE type=TR AND name=student_delete)DROP TRIGGER student_deleteGO14第14页,本讲稿共40页CREATE TRIGGER student_delete ON studentFOR DELETEASDECLARE NumOfStudent TINYINTSELECT NumOfStudent=c.student_num FROM class c,deleted d WHERE c.class_id=d.class_idIF (NumOfStudent 0)BEGIN UPDATE class S
17、ET student_num=student_num-1 FROM class c,deleted d WHERE c.class_id=d.class_id END15第15页,本讲稿共40页ELSE BEGIN UPDATE class SET student_num=(SELECT COUNT(s.student_id)FROM student s,deleted d WHERE s.class_id=d.class_id)FROM class c,deleted d WHERE c.class_id=d.class_id ENDGO在class表中student_num列的值自动减列的
18、值自动减1的原因是:的原因是:在student表上执行删除学生记录的操作时,触发了student表上的删除触发器,该触发器将class表上的student_num字段值减1。在上述定义触发器时,使用了deleted逻辑表。deleted表是一个逻辑表,在执行删除触发器语句时,表中被删除的行存放在deleted表中。16第16页,本讲稿共40页下面我们来看看整个删除触发器的执行过程:整个删除触发器的执行过程:首先执行DELETE语句执行删除。系统检查删除语句的正确性及是否违反数据完整性(如:约束等),如果正确,将从student表中删除该行,并将删除的旧行存放在deleted表中。执行触发器中的
19、相应语句,修改class表中相应列的信息。如果执行过程中某个环节出现错误,或执行到ROLLBACK语句,则系统将回滚整个操作。17第17页,本讲稿共40页4.创建创建UPDATE触发器触发器在实际的教务管理中,可能会有教师在各个院系之间进行工作调动,一方面需要更新teacher表中相关教师的department_id列的内容;另一方面,一个教师从一个系调动到另一个系,会影响两个系的教师总人数,这就需要更新这两个系的教师总人数。现在来为teacher表建立一个更新触发器,实现系信息表department中相关列的自动更新。【例例12-3】为teacher表建立UPDATE触发器,在教师数据变更时
20、自动更新department表的教师人数。USE jwglGO/*如果存在同名的触发器,则删除之*/IF EXISTS (SELECT name FROM sysobjectsWHERE type=TR AND name=teacher_update)DROP TRIGGER teacher_updateGO18第18页,本讲稿共40页/*建立更新触发器*/CREATE TRIGGER teacher_update ON teacherFOR UPDATEASUPDATE department SET teacher_num=(SELECT COUNT(t.teacher_id)FROM te
21、acher t,inserted iWHERE t.department_id=i.department_id)FROM department d,inserted iWHERE d.department_id =i.department_idUPDATE department SET teacher_num=(SELECT COUNT(t.teacher_id)FROM teacher t,deleted eWHERE t.department_id =e.department_id)FROM department d,deleted eWHERE d.department_id=e.dep
22、artment_idGO19第19页,本讲稿共40页下面我们来验证一下这个触发器的功能。1.首先看看当前department表中各系的数据,执行 SELECT*FROM department 语句,语句,系统显示的执行结果如下:department_id department_name department_header teacher_num dep_01 无线电无线电 王敬远王敬远 1dep_02 通信与信息工程通信与信息工程 康辉康辉 1dep_03 电子工程电子工程 董一平董一平 2dep_04 计算机科学计算机科学 纪云纪云 52.然后我们修改一个教师的department_id,然
23、后再查询department表的数据:UPDATE teacher SET department_id=dep_01 WHERE teacher_name=潘惠潘惠20第20页,本讲稿共40页3.SELECT*FROM department结果如下:department_id department_name department_header teacher_num dep_01 无线电无线电 王敬远王敬远 2dep_02 通信与信息工程通信与信息工程 康辉康辉 1dep_03 电子工程电子工程 董一平董一平 1dep_04 计算机科学计算机科学 纪云纪云 5现在,由于一个教师从“电子工程”系
24、调到了“无线电”系,“无线电”系的教师人数增加为2,而“电子工程”系的教师人数减少为1。这个UPDATE触发器的功能实现了。21第21页,本讲稿共40页在对teacher表进行UPDATE操作时,触发了更新触发器teacher_update,该触发器将相关教师原先所在的系和现在所在的系的教师人数都重新进行了统计更新。由于teacher表在进行UPDATE操作时,把更新前后的数据值分别拷贝到了deleted和inserted临时表中。所以可以从这两个表中得到这个教师调动前后两个相关的department_id,从而对department表中的两行进行重新统计教师人数。从整体性能方面考虑,需要注意
25、一个问题:注意一个问题:一个表的更新触发器一旦建立,那么只要对该表中的数据进行更新,这种更新无论是对表中的一行或多行,还是一列或多列,都将执行触发器操作。而在实际应用中,可能只关心对特定列是否被更新,比如上面例子中我们只关心teacher表的department_id是否更新,如果特定的列被更新,则执行触发器操作,否则不执行触发器操作。在设计更新触发器时可以通过IF UPDATE 来实现。在同一个触发器的定义语句中,可以使用多个IF UPDATE语句来对不同的列的修改执行不同的触发器操作。22第22页,本讲稿共40页【例例12-4】根据示例3,使用IF UPDATE进行优化,只对teacher
26、表特定列的更新作出触发器操作。USE jwglGO/*如果存在同名的触发器,则删除之*/IF EXISTS (SELECT name FROM sysobjectsWHERE type=TR AND name=teacher_update)DROP TRIGGER teacher_updateGO/*建立更新触发器*/CREATE TRIGGER teacher_update ON teacherFOR UPDATEAS/*如果更新teacher表的department_id列,则执行对department表teacher_num列的更新*/23第23页,本讲稿共40页IF UPDATE(de
27、partment_id)BEGIN UPDATE department SET teacher_num=(SELECT COUNT(t.teacher_id)FROM teacher t,inserted iWHERE t.department_id=i.department_id)FROM department d,inserted i WHERE d.department_id=i.department_id UPDATE department SET teacher_num=(SELECT COUNT(t.teacher_id)FROM teacher t,deleted eWHERE
28、t.department_id=e.department_id)FROM department d,deleted e WHERE d.department_id=e.department_idENDGO24第24页,本讲稿共40页12.2.2 使用使用SQL Server Management Studio创建触发器创建触发器在SQL Server Management Studio中使用以下步骤创建触发器:1)打开SQL Server Management Studio。2)分别展开“数据库”、“JWGL”、“表”。3)点击将在其上创建触发器的表(如student),再右击“触发器”,在系
29、统弹出的快捷菜单上单击“新建触发器”,系统文档窗口触发器创建模板。4)在触发器创建模板上输入触发器创建文本。5)点击工具栏上的执行按钮,完成触发器的创建,如需保存触发器创建文本,点击工具栏上的保存按钮。本章首页本章首页本章首页本章首页25第25页,本讲稿共40页12.3 触发器实施数据完整性实例12.3.1 实现参照完整性实现参照完整性触发器能够维持两个表间的参照完整性(Referential Integrity),就像外键一样。外键执行这个任务的效率更高,因为它们在数据改变之前被测试,而不像触发器在数据改变后才触发。但通过使用T-SQL代码,它可以包含复杂的处理逻辑,便于成功实现级联删除和更
30、新。下面一个例子说明了触发器如何实现参照完整性。【例例12-5】向teacher_course_class表添加一行数据,检查所插入数据的有效性。确保教师(teacher_id)存在teacher表中,课程(course_id)存在于course表中,而班级(class_id)必须存在于class表中。使用下面的代码来定义teacher_course_class表INSERT触发器:CREATE TRIGGER tcc_insert ON teacher_course_classFOR INSERTAS26第26页,本讲稿共40页IF(NOT EXISTS(SELECT teacher_id
31、FROM teacher WHERE teacher_id IN(SELECT teacher_id FROM inserted)OR(NOT EXISTS(SELECT course_id FROM course WHERE course_id IN (SELECT course_id FROM inserted)OR(NOT EXISTS(SELECT class_id FROM class WHERE class_id IN(SELECT class_id FROM inserted)BEGIN PRINT 添加记录操作不能完成!PRINT 输入的教师编号、课程编号或班级编号有错误。RO
32、LLBACK TRANSACTIONEND27第27页,本讲稿共40页当tcc_insert触发器被触发时,将检查teacher、course和class表,测试inserted临时表中的teacher_id、course_id和class_id是否存在这三个表中。如果某一项不存在则撤消添加操作。12.3.2 实施特殊业务规则实施特殊业务规则实现一些特殊业务规则是触发器运用的一个重要方面。例如,如果一个教师正在为某些班级的课程授课,则不能删除这个教师的数据。【例例12-6】定义teacher表的DELETE触发器,实施“正在授课的教师数据不能删除”这个业务规则:CREATE TRIGGER t
33、eacher_delete ON teacherFOR DELETEASIF(EXISTS (SELECT teacher_id FROM teacher_course_class 28第28页,本讲稿共40页WHERE teacher_id IN (SELECT teacher_id FROM deleted)BEGIN PRINT 删除记录操作不能完成!PRINT 该教师正在为一些班级授课。ROLLBACK TRANSACTION returnEND系表的相应系的人数的更改!GO本章首页本章首页本章首页本章首页29第29页,本讲稿共40页12.4 查看、修改和删除触发器12.4.1 查看触
34、发器信息查看触发器信息使用T-SQL语句或SQL Server Management Studio可以获取表中触发器的类型、触发器名称、触发器所有者,以及触发器创建的日期。如果触发器创建或修改时没有进行加密,还可以获取触发器定义的有关信息,了解它如何影响所在的表。由于触发器也是一种特殊的存储过程,所以触发器被创建以后,它的名字存放在系统表sysobjects中,它的创建源代码存放在syscomments系统表中。1.使用使用T-SQL语句查看触发器信息语句查看触发器信息 查看表中的触发器信息使用系统存储过程sp_helptrigger可以查看指定表中所定义的触发器及它们的类型。例如,要查看st
35、udent表中触发器信息,可使用下列语句:EXEC sp_helptrigger student30第30页,本讲稿共40页 查看触发器定义查看触发器定义使用系统存储过程sp_helptext可以查看指定触发器的定义文本。例如,要查看student_insert触发器的定义代码,就可以使用下列语句:EXEC sp_helptext student_insert在查询分析器中可以看到如图12-4所示执行界面和结果。图12-4 使用系统存储过程查看触发器定义 查看触发器的相关性查看触发器的相关性使用系统存储过程sp_depends可以查看指定触发器的相关性,了解触发器所依赖的表或视图。例如,可以使
36、用下面的语句来查看student_delete触发器的相关性:EXEC sp_depends student_delete31第31页,本讲稿共40页2.使用使用SQL Server Management Studio查看触发器依查看触发器依赖关系赖关系1)展开服务器。2)分别展开“数据库”、“JWGL”、“表”、含触发器的表、“触发器”。3)右击要查看依赖关系的触发器,然后单击“查看依赖关系”。4)查看完毕点击“确定”即可。32第32页,本讲稿共40页12.4.2 修改触发器修改触发器1.使用使用T-SQL语句修改触发器语句修改触发器使用T-SQL语句ALTER TRIGGER可以修改触发器
37、,它的语法与CREATE TRIGGER类似。具体语法形式如下:ALTER TRIGGER trigger_name ON tablename WITH ENCRYPTION FOR DELETE ,INSERT ,UPDATE ASsql_statement在以上语法形式中:trigger_name:要更改的触发器名称。tablename:指定触发器在其上执行的表或视图名字。WITH ENCRYPTION:加密触发器的定义成本。FOR DELETE,INSERT,UPDATE:指定所更改的触发器将在发生哪些事件时被触发 sql_statement:指定触发器执行的SQL语句。33第33页,本
38、讲稿共40页2.使用使用SQL Server Management Studio修改触发器修改触发器使用SQL Server Management Studio对触发器进行修改的具体步骤如下:1)展开服务器。2)分别展开“数据库”、“JWGL”、“表”、含触发器的表、“触发器”。3)右击要查看修改的触发器,然后单击“修改”即可。34第34页,本讲稿共40页12.4.3 删除触发器删除触发器当不再需要某个触发器时,可将其删除。当触发器被删除时,它所基于的表和数据并不受影响。删除表将自动删除其上的所有触发器。1.使用使用T-SQL语句删除触发器语句删除触发器使用DROP TRIGGER语句可以从当
39、前数据库某个表中删除一个或多个触发器。其语法如下所示:DROP TRIGGER trigger ,.n 参数:trigger:要删除的触发器名称。n:表示可以删除多个触发器的占位符。【例例12-7】删除触发器student_delete,执行如下的语句。USE jwglIF EXISTS (SELECT name FROM sysobjects WHERE name =student_delete AND type =TR)DROP TRIGGER student_deleteGO35第35页,本讲稿共40页2.使用SQL Server Management Studio删除触发器在SQL S
40、erver Management Studio中,使用以下步骤删除触发器:1)展开服务器。2)分别展开“数据库”、“JWGL”、“表”、含触发器的表、“触发器”。3)右击要删除的触发器,然后单击“删除”。4)在系统弹出的“删除对象”对话框上点击“确定”即可。本章首页本章首页本章首页本章首页36第36页,本讲稿共40页12.5 使用触发器的注意事项1.触发器的嵌套和递归如果一个触发器在执行操作时引发了另一个触发器,而这个触发器又接着引发下一个触发器这些触发器就是嵌套触发器。触发器可嵌套至32层,并且可以控制是否可以通过“嵌套触发器”服务器配置选项进行触发器嵌套设置。如果允许使用嵌套触发器,且链中
41、的一个触发器开始一个无限循环,当超出嵌套级数时,触发器将终止。例如,在student表中删除一行学生记录时触发了触发器student_delete,该触发器对class表中学生所在班级的student_num进行重新统计。可以为class表建立更新触发器class_update_student_num,在学生人数变动时更新department表中学生所在院系的学生总人数(该数据由统计class表中所有本系的班级学生人数得到)。这种嵌套关系如图12-5所示。student表deletestudent_delete37第37页,本讲稿共40页触发器class表class_update_studen
42、t_num触发器department表图12-5 嵌套触发器关系示意由于触发器在事务中执行,如果在一系列嵌套触发器的任意层中发生错误,则整个事务都将取消,且所有的数据修改都将回滚。可以在触发器中包含PRINT语句,用以显示错误发生的位置。在设置了RECURSIVE_TRIGGERS数据库选项后,触发器可以以递归方式调用。所谓递归触发器,是指当触发器被触发执行时修改了自己在其上被定义的表或相关的表,由于这些表的更新从而再一次引起该触发器的触发,如此循环直到某个条件限定终止触发或超出系统对递归的限制。2.约束检查优于触发器检查如果在触发器表上有约束,那么这些约束在触发器执行前进行检查。如果操作与约
43、束冲突,那么触发器将不执行。student表deletestudent_delete触发器class表class_update_student_num触发器department表38第38页,本讲稿共40页3.触发器中的T-SQL限制触发器中不允许使用以下T-SQL语句:ALTER DATABASECREATE DATABASEDISK INITDISK RESIZEDROP DATABASELOAD DATABASELOAD LOGRECONFIGURERESTORE DATABASERESTORE LOG39第39页,本讲稿共40页4.关于多行触发器的注意事项在使用触发器时需要考虑的一个重要问题就是:当插入、删除、修改多个记录行时,必须使用能处理多行记录的触发器。引发触发器的操作可能是对触发器表多行的操作,而不仅是影响一行的操作。这在UPDATE和DELETE触发器中很常见,因为数据更新、删除语句经常作用于多行。尽管引发INSERT触发器的INSERT语句只添加一行数据,但INSERT触发器也可由能影响触发器表多行的INSERT INTO(table_name)SELECT语句所激发。为了避免出现错误结果,在编写触发器代码时必须考虑适应inserted和deleted表中出现多行的可能性。本章首页本章首页本章首页本章首页40第40页,本讲稿共40页