摘 要: 针对初学者容易混淆AFTER触发器与INSTEAD OF触发器的问题,首先用通俗的语言对触发器进行了概述,接着阐述了触发器的工作原理,然后结合实例分析了AFTER触发器与INSTEAD OF触发器的主要区别与应用,最后总结了触发器应用的注意事项。
关键词: SQL Server;数据库;触发器;AFTER;INSTEAD OF
0 引言
触发器是SQL Server数据库教学中的重要内容之一,触发器的教学重点是DML触发器的创建、管理与应用,而DML触发器的难点是AFTER触发器与INSTEAD OF触发器的区别与应用。初学者往往对此比较容易混淆,不知道何时选用AFTER触发器、何时选用INSTEAD OF触发器。为此,本文对SQL Server数据库中DML触发器的教学内容进行优化探讨,以帮助初学者准确快速地掌握DML触发器的精髓。
1 触发器概述
触发器是一种特殊的存储过程,它是针对表或视图定义的数据库对象,它不能被显式地调用,而是当对定义了触发器的表或视图进行Create、Alter或Drop操作时,或者对定义了触发器的表或视图进行Insert、Update或Delete操作时,触发器才被自动执行。在触发器中主要是定义通过主键、外键、默认值或CHECK约束等无法实现的复杂的参照完整性和数据完整性的业务逻辑。当表或视图被删除时,其上定义的触发器也一同被删除[1]。使用触发器主要有以下几点优点:
(1)级联修改数据库中的所有相关表。
(2)撤销或回滚违反引用完整性的操作,防止非法数据修改。
(3)强制执行比外键参照完整性、CHECK约束更为复杂的业务逻辑。
(4)查找在数据修改前后表状态之间的差别,并根据差别分别采取相应的措施。
(5)触发器是自动执行的,不需要管理员手动维护数据库的数据完整性[2]。
需要注意以下几点:
(1)只有表的所有者才可以在表上创建或删除触发器,且这种权限不能转授。
(2)可以在触发器中引用临时表,但不能在临时表上创建触发器。
(3)在执行修改语句的过程中,触发器的执行是执行修改语句的一部分,所以如果触发器执行不成功则整个事务回滚[3]。
在SQL Server2008中,触发器主要有DML(Data Manipulation Language)触发器、DDL(Data Definition Language)触发器和登录触发器。其中DML触发器又可以分为6种类型:AFTER-INSERT触发器、AFTER-UPDATE触发器、AFTER-DELETE触发器与INSTEAD OF-INSERT触发器、INSTEAD OF-UPDATE触发器、INSTEAD OF-DELETE触发器[1]。
2 触发器工作原理
触发器被触发时,系统将在内存中自动创建两个特殊的临时表,分别是INSERTED表和DELETED表。INSERTED表用于存储INSERT和UPDATE语句所影响的记录行的副本。DELETED表用于存储DELETE和UPDATE语句所影响的记录行的副本。INSERTED表和DELETED表只是存储于内存的逻辑表,而不是存储在数据库中的物理表,但其结构与触发器所关联的表结构一致。
这两个表由系统进行创建和管理,用户不允许直接读取和修改其内容,但可以在触发器中访问它们的数据。当触发器执行完毕后,这两个表由系统自动删除[4]。
当通过插入(INSERT)语句引发触发器时,新的记录的副本会添加到临时表INSERTED表中。当通过删除(DELETE)语句引发触发器时,被删除的记录会添加到临时表DELETED表中。当通过更新(UPDATE)语句引发触发器时,首先删除原有的旧记录,并将该被删除的记录添加到临时表DELETED表中,然后添加更新后的新记录,并将更新后的新记录添加到临时表INSERTED表中。在触发器内部可以引用INSERTED表和DELETED表中相关数据实现数据的操纵。
创建触发器的基本语法结构如下:
CREATE TRIGGER [<所有者名称>.]<触发器名> /*指明
触发器的名称*/
ON { <表名> | <视图名> } /*指定触发器依赖的基表或视
图*/
[ WITH ENCRYPTION ] /*指定对触发器的源码进行加密*/
{
{ { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [,][DELETE]}
AS
[BEGIN]
<T-SQL语句>[ ...n ] /*指定触发器执行的SQL语句,
是触发器的核心*/
[END]
}
}
说明:上面基本语法结构中,INSERT、UPDATE、DELETE选项用来指定触发器的事件类型,三个选项至少要指定一个,允许任意次序组合这三个选项。FOR与AFTER关键字含义完全相同,与INSTEAD OF一起组成指定触发的方式,AFTER为后触发,INSTEAD OF为替代触发。
3 AFTER触发器与INSTEAD OF触发器的区别
AFTER触发器也称后触发,是只有执行了某一个操作(如INSERT、UPDATE、DELETE等)之后,触发器才被触发。也即只有引发触发器的操作语句已经完成,并通过各类约束验证后才会去执行触发器的语句;如果引发触发器的操作语句有错误或违反了约束而导致执行失败,触发器是不会执行的。
INSTEAD OF触发器也称替代触发,该类型触发器并不会执行引发触发器的操作语句(如INSERT、UPDATE、DELETE等T-SQL语句),而只是去执行触发器里面的T-SQL语句。即由触发器里面的T-SQL语句替代引发触发器的T-SQL语句的执行。
假如在一个StudentManager数据库中有tbStudent表及tbDepartment表,两个表的结构如表1、表2所示(由于只是为了说明问题,在此对表结构做了简化处理)。
现假定tbStudent表中有如下3条记录:1001,张三,女,1;1002,李四,男,2;1003,王五,男,3。tbDepartment表中有如下4条记录:1,计算机系,小张;2,艺术系,小李;3,服装工程系,小朱;4,物理系,老谭。
例:假如要从tbDepartment表中删除某系部信息,如果该系部下存在学生信息,则不允许删除,要求利用触发器来实现。
现编写替代触发器delete_DepInfo_instead,代码如下:
USE StudentManager
GO
CREATE TRIGGER delete_DepInfo_instead ON tbDepartment
INSTEAD OF DELETE -- 替代触发
AS
-- 从表deleted中获取删除记录的部门编号
DECLARE @depid varchar(20)
DECLARE @stuname varchar(20)
SELECT @depid = DepID FROM deleted
-- 判断要删除的部门编号是否存在学生信息
SELECT @stuname= StuName FROM tbStudent WHERE DepID=@depid
IF @stuname IS NOT NULL
PRINT '指定系部存在学生,请先删除或修改学生信息!' -- 提示错误信息
ELSE
DELETE FROM tbDepartment WHERE DepId=@depid
GO
编写引发该触发器T-SQL语句代码如下:
USE StudentManager
GO
DELETE FROM tbDepartment WHERE DepId=1
GO
结果分析:由于tbStudent表中存在系部编号为1的学生信息,所以结果为弹出“指定系部存在学生,请先删除或修改学生信息!”。但是把引发触发器的SQL语句修改为“DELETE FROM Department WHERE DepId=4”,由于在学生表tbStudent中不存在系部编号为4的学生信息,所以会执行触发器本身所含的“DELETE FROM tbDepartment WHERE DepId=@depid”SQL语句删除系部编号为4的系部信息,而不是通过引发触发器的SQL语句“DELETE FROM tbDepartment WHERE DepId=4”删除系部编号为4的系部信息。换句话说假如上面触发器delete_DepInfo_instead中T-SQL语句中没有“ELSE DELETE FROM tbDepartment WHERE DepId=@depid”语句,即使引发该触发器T-SQL语句要删除系部编号为4的记录(DELETE FROM tbDepartment WHERE DepId=4),也不能完成删除操作。
但是如果把上面触发器(delete_DepInfo_instead)修改为后触发的触发器(delete_DepInfo_after):
USE StudentManager
GO
CREATE TRIGGER delete_DepInfo_after ON tbDepartment
after DELETE -- 后触发
AS
-- 从表deleted中获取删除记录的部门编号
DECLARE @depid varchar(20)
DECLARE @stuname varchar(20)
SELECT @depid = DepID FROM deleted
-- 判断要删除的部门编号是否存在学生信息
SELECT @stuname= StuName FROM tbStudent WHERE DepID=@depid
IF @stuname IS NOT NULL
PRINT '指定系部存在学生,请先删除或修改学生信息!' -- 提示错误信息
ELSE
DELETE FROM tbDepartment WHERE DepId=@depid
GO
编写引发该触发器T-SQL语句代码如下:
USE StudentManager
GO
DELETE FROM tbDepartment WHERE DepId=4
GO
结果是不论触发器T-SQL语句中有没有“ELSE DELETE FROM tbDepartment WHERE DepId=@depid”语句,系部编号为4的记录都将删除,因为此时会先执行引发触发器的T-SQL语句(DELETE FROM tbDepartment WHERE DepId=4),从而把系部编号为4的记录删除。
此外,AFTER触发器只能定义在表上,INSTEAD OF触发器可以定义在表上,也可以定义在视图上。一个表上可以定义多个AFTER触发器,但是只能在一个表或视图上定义一个INSTEAD OF触发器。
4 触发器应用注意事项
触发器功能强大,可轻松地实现许多复杂的功能。触发器主要用来实现比较复杂的数据完整性、一致性。例如监督某一列数据的变化范围,并在超出规定范围以后,对两个以上的表进行修改。但当使用约束、规则、默认值就可以实现数据完整性时,应优先使用前三种措施,因为滥用触发器会造成数据库及应用程序维护困难。对表执行修改操作时,约束优先于触发器。如果约束和触发器发生冲突,触发器将被屏蔽,不再执行。一般来说,只要不影响数据的修改,AFTER触发器比INSTEAD OF触发器效率更高,因此,AFTER触发器和INSTEAD OF触发器都能实现某功能需求时,优先选用AFTER触发器。
5 结束语
DML触发器是用得最广泛的触发器,在SQL SERVER教学中占有重要的地位。教学中的难点往往是ALTER触发器与INSTEAD OF触发器的区别与应用。本文通过通俗的语言对触发器进行了概述,阐述了触发器被触发时两个临时逻辑表INSERTED表和DEKETED表的作用,结合实例分析了AFTER触发器与INSTEAD OF触发器的主要区别与应用。AFTER触发器为后触发器,也即AFTER触发器会先执行引发触发器中的T-SQL语句,后再执行触发器本身的T-SQL语句,而INSTEAD OF触发器为替代触发器,即通过执行触发器中的T-SQL语句来替代执行引发触发器的T-SQL语句,也即INSTEAD OF触发器中引发触发器的T-SQL语句不会执行。
参考文献
[1] 高晓黎,韩晓霞. SQL Server2008案例教程[M]. 北京:清华大学出版社, 2010.
[2] 邱李华,李晓黎,任华,等. SQL Server 2008数据库应用教程(第2版)[M]. 北京:人民邮电出版社, 2012.
[3] 仝春灵,沈祥玖. 数据库原理与应用[M]. 北京:中国水利水电出版社, 2006.
[4] 程志梅,邱霞明,王晓燕. SQL Server2000数据库中触发器的妙用[J]. 计算机应用与软件, 2009(3):188-189.