我对触发器的理解:
- 简单理解...触发器就是事件,在特定的情况下自动执行. 但与事件有点不同!
- 触发器与表或视图连接在一起.
-----------------------------------------------猥琐的分割线-------------------------------------------------
触发器用于以下场景:
级联
从SQL SERVER 2000 开始, 就有级联删除或更新, 这时使用触发的原则是, 只有在内置级联功能和生命的完整性功能不能提供期望的结果或根本不存在时, 才考虑使用触发器. 原因:内置功能更加有效....
检查
不解
规则实施者
有些用户可能只是做一些开发人员或DBA(DataBase Administrator? 还不让我猜出来了!)预料不到的事情, 而有些用户则违反企业或组织原则去访问数据库. 触发器可以确保无法在表中尝试执行某些操作. 可以发出警报, 捕获连接信息.
评估机制
使用触发器评估DML在表或视图上执行操作之前和之后的数据状态.
友情提示: DML:数据操作语言 update insert delete等...........(好高深的东西啊!!!!!!!!故弄玄虚!!!!!!!!恨死不理解的缩写了!!!!!!!)
-----------------------------------------------猥琐的分割线-------------------------------------------------
触发器代码不允许出现:
- ALTER DATABASE
- CREATE DATABASE
- DROP DATABASE
- LOAD DATABASE
- RESTORE DATABASE
- DISK INIT
- DISK RESIZE
- RECONFIGURE
- LOAD LOG
- RESTORE LOG
尽管触发器可以使用SELECT语句, 并生成结果返回, 但缉获触发器的客户端通常无法解释或处理返回的数据. 为此. 应避免打开SELECT. 所谓打开指结果集未分配给内部结构. 应该在触发器的开头使用SET NOCOUNT, 避免将任何数据返回到客户端. 要尽量避免在触发器中使用光标(啥东西?),因为如果滥用,会用尽服务器资源. 如果要处理触发器代码中的多个行, 都应该使用rowset(啥东西TOO)功能.
注意TRUNCATE TABLE(一个一并删除操作, 通过取消分配表的数据页来清空表)操作其间, 触发器会被取消. WRITETEXT不激活触发器.
-----------------------------------------------------猥琐的分割线---------------------------------------------------
触发器执行类型:
可以确定触发器的执行时间. 除了FOR子句, 可以定义触发器的两种执行类型.
AFTER 触发器在激活它的语句完成后才激活. 默认做法. 如果DML语句失败, AFTER触发器不激活. 一个表上可以有多个AFTER触发器, 不支持视图. 出现违反约束情况, AFTER永远不执行.
INSTEAD OF触发器激活将代替实际的触发操作. 就是触发 触发器的DML语句并不执行, 而被触发器代替. 可以为表或视图定义INSTEAD OF触发器. 能更新视图数据(平时视图并不更新).
--------------------------------------------------猥琐的分割线---------------------------------------创建触发器
可以用T-SQL, Management Studio 或查询分析器, SQL-SMO触发器集合进行创建. 也可以用.NET语言编写, 运行程序创建. 一般用前两者
T-SQL创建触发器
CREATE TRIGGER[ schema_name .]trigger_name //数据库名
ON { table | view} //受益者..
[ WITH < dml_trigger_option > [, ....n] ]
{FOR | AFTER | INSTEAD OF} //执行类型
{ [INSERT] [,] [UPDATE][,][DELETE]} //什么事件执行
[ WITH APPEND]
[NOT FOR REPLICATION]
AS { sql_statement [;] [, ...n] | EXTERNAL NAME <method specifier [;]>}
//每次DML事件发生在表或视图上时, 要执行的T-SQL代码
<dml_trigger_option> ::=
[ENCRYPTION]
[EXECUTE AS Clause]
<method_specifier> ::=
assembly_name.class_name.method_name
CREATE TRIGGER trigger_name
ON {ALL SERVER | DATABASE}
[WITH <ddl_trigger_option> [, ...n]]
{FOR | AFTER} {event_type | event_group } [, ...n]
AS {sql_statement[;] [, ...n] | EXTERNAL NAME <method specifier> [;]}
ddl_trigger_option ::=
[ENCRYPTION]
[EXECUTE AS Clause]
<method_specifier> ::=
assembly_name.class_name.method_name
NOT FOR REPLICATION如果复制导致了表操纵, 则不执行触发器
------------------------------------------------------猥琐的分割线-------------------------------------------
编写触发器
可以使用IF UPDATE(column_name)子句来确定激活触发器的DML语句或更早的语句, 是否修改了对应的列(包括修改和添加).
CREATE TRIGGER myTrigger
ON myTable
FOR INSERT
AS IF UPDATE(column_X)
EXEC DotNetMailer.Send 'Jshapiro' , 'Column X Updated''
或使用IF COLUMNS_UPDATED()子句来检查INSERT或UPDATE语句更新了表中的哪些列. 使用整数位掩码来指定要测试的列.
CREATE TRIGGER myTrigger
ON myTable
FOR INSERT
AS IF (COLUMN_UPDATE() & 1 = 1)
EXEC DotNetMailer.Send 'Jshapiro', 'Column X Updated'
但上述方法不能检测是否删除了字段.
可以使用@@ROWCOUNT函数检查行删除. 此函数返回上一查询所影响的行数
@@ROWCOUNT返回删除的行数, 形式是@@ROWCOUNT = X. 如果@@ROWCOUNT = 0则上次执行的语句没影响任何行, 若大于0则影响到@@ROWCOUNT行(如果是删除, 则返回删除的行数).
-----------------------------------------------猥琐的分割线-------------------------------------
第一个触发器和最后一给触发器
如果在特定表上写了很多个AFTER触发器, 则可以定义哪个是第一个触发器, 哪个是最后一个触发器
AFTER/FOR可以定义第一个触发器和最后一个触发器.
INSTEAD OF 触发器不能
第一个触发器不能作为最后一个触发器.
第一个触发器和最后一个触发器之间的触发器执行是无序的.
如果更改第一个和最后一个触发器, 将会删除其第一或最后的状态
可以使用sp_settriggerorder来指定AFTER/FOR触发器的第一个和最后一个属性
First~~~~Last~~~~None
eg:
sp_settriggerorder @triggername='myTrigger', @order='first'
--------------------------------------------猥琐的分割线--------------------------------------------------
触发器递归
间接:语句触发了TableA的Trigger1, Trigger1导致了一个事件激活TableB的Trigger2, Trigger2又激活了Trigger1
直接:语句触发了TableA的Trigger1, Trigger1导致了一个事件激活了TableA的Trigger2, Trigger2又激活了Trigger1
可以使用sp_dboption存储过程禁用直接递归, 但这会起用间接递归
可以使用sp_configure来禁用两种递归
---------------------------------------------------猥琐的分割线-----------------------------------
触发器嵌套
可以嵌套触发器, TableA的触发器激活了TableB, TableB的触发器激活了TableC, TableC的触发器激活了TableD......不能超过32级.
可以使用sp_configure禁用
--------------------------------------------------猥琐的分割线---------------------------------------------
更改触发器
ALTER TRIGGER trigger_name
删除触发器
DROP TRIGGER [x, y, z]
删除触发器前, 要确保使用sp_depends存储过程来检查触发器依赖性.
获取触发器信息
EXEC sp_helptrigger Items