触发器包含:dml触发器和ddl触发器。

dml触发器包含了用于对表或视图的insert、update、delete操作做出响应的T-SQL代码,而ddl触发器对服务器或数据库事件做出响应而不是数据修改。

触发器能够自动响应某种行为,所以对于必须对某种行为做出业务级别响应的情况,触发器很合适。

在用触发器时,需要注意的:

1、触发器通常比较隐蔽,很容易被忘记,在检查性能或逻辑问题的时候,经常会忘记触发器是在后台执行的,要确保在文档中记录了触发器。

2、如果所有的数据修改流程都通过存储过程完成,那么尽可能不要使用触发器。

3、始终需要保证性能,确保能快速执行且没有bug。长时间运行的触发器会严重减慢数据修改操作,所有在数据修改比较频繁的数据库中使用触发器需要特别小心。

4、不记录日志的更新不会引起dml触发器的触发,如:writetext,truncate table、批量导入操作。

5、约束通常比dml触发器运行更快,因此如果约束能满足业务的需要,则使用约束来代替。由于after触发器是在数据修改之后触发的,所以不能防止违反约束。

6、不允许在触发器中使用select语句来返回结果集。

create table dbo.t 	(vid int not null primary key, 	 v varchar(100) , 	 vv varchar(10) 	) 	 	 select * into dbo.t_insert from dbo.t  select * into dbo.t_update from dbo.t  select * into dbo.t_delete from dbo.t   insert into dbo.t(vid,v,vv) values(1,'a','aaa'),       (2,'b','bbb'),       (3,'c','ccc'),       (4,'d','ddd'),       (5,'e','eee')   --创建after dml触发器 create trigger dbo.t_after on dbo.t after insert,delete as  insert into dbo.t_insert select * from inserted  insert into dbo.t_delete select * from deleted  go  --触发 insert into dbo.t values(6,'f','ffff')   --发现已经添加到表中 select * from dbo.t_insert
--1.创建instead of触发器 create trigger dbo.t_instead_of on dbo.t with encryption instead of insert             not for replication as  declare @v varchar(100) set @v = ''  select @v = V  from inserted  if (@v = 'a')    rollback    --回滚  /*========================================= 引用插入的列只能在select语句中使用, 而不能单独引用:  if(inserted.v = 'a')   rollback   无法绑定由多个部分组成的标识符 "inserted.v" ===========================================*/ go   --事务在触发器中结束。批处理已中止。 insert into dbo.t values(7,'a','aaa')    --2.修改触发器,根据修改列控制触发器 alter trigger dbo.t_instead_of on dbo.t with encryption instead of insert             not for replication as  declare @v varchar(100) set @v = ''  select @v = V  from inserted  --如果在v列上执行insert或update,那么update(v)返回true if (@v = 'a' or UPDATE(v))    rollback    --回滚  /*========================================= 引用插入的列只能在select语句中使用, 而不能单独引用:  if(inserted.v = 'a')   rollback   无法绑定由多个部分组成的标识符 "inserted.v" ===========================================*/ go   --由于更新了v列,所以事务在触发器中结束。批处理已中止。 insert into dbo.t values(7,'g','g')
--1.创建数据库级别触发器 create trigger wcc on database for create_table as  raiserror( 'A error occur,please retry again!',16,1) rollback  go  /*======================================= 消息 50000,级别 16,状态 1,过程 wcc, A error occur,please retry again! 消息 3609,级别 16,状态 2,第 1 行 事务在触发器中结束。批处理已中止。 =========================================*/ create table www(vid int not null)    --2.1在master数据库中建立服务器级别跟踪表 use master go  create table server_eventdata 	(eventdata xml,      principal_user nvarchar(100),      login_user nvarchar(100)     )           --2.2建立服务器级别触发器 create trigger gyy_server on all server for create_table,drop_table,create_index as  insert into server_eventdata select EVENTDATA(),USER,SUSER_NAME() go  --2.3会触发服务器级别触发器 create table www(vid int not null)  --查看记录的事件 select * from server_eventdata

触发器元数据、管理触发器

--1.dml触发器元数据 select o.name,        t.name,        t.parent_class_desc,       --对象或列                t.type,                       t.type_desc,               --触发器        is_not_for_replication,  --在对表进行复制修改时不执行触发器        is_instead_of_trigger,   --是否是instead of触发器                s.definition from sys.triggers t inner join sys.objects o         on t.parent_id = o.object_id inner join sys.sql_modules s         on s.object_id = t.object_id   --2.数据库级别ddl触发器元数据 select t.name,                T.parent_class,        T.parent_class_desc,        T.type_desc,                S.definition from sys.triggers t inner join sys.sql_modules s         on s.object_id = t.object_id where parent_id =0       and parent_class_desc ='DATABASE'   --3.服务器级别ddl触发器元数据 SELECT ST.name,        parent_class,        parent_class_desc,        type_desc,                SSM.definition FROM SYS.server_triggers ST INNER JOIN SYS.server_sql_modules SSM         ON ST.object_id = SSM.OBJECT_ID WHERE parent_class_desc = 'SERVER'    --4.1限制触发器嵌套,服务器范围的选项 use master go  --禁止触发器嵌套 exec sp_configure 'nested triggers',0 reconfigure with override go  --启用触发器嵌套 exec sp_configure 'nested triggers',1 reconfigure go  --4.2控制触发器递归,数据库范围的选项 --允许递归,after触发器仍然受到32层嵌套的限制 alter database wcc set recursive_triggers on  --禁止递归 alter database wcc set revursive_triggers off  --查看数据库是否允许触发器递归 select is_recursive_triggers_on from sys.databases   --5.1禁用某个表的某个触发器 disable trigger dbo.t_after on dbo.t  --5.2禁用某个表的所有触发器 disable trigger all on dbo.t  --5.3禁用某个数据库的某个数据库触发器 disable trigger wcc on database  --5.4禁用某个数据库的所有数据库触发器 disable trigger all on database  --5.5禁用服务器上的某个触发器 disable trigger gyy_server on all server  --5.6禁用服务器上所有的服务器级别触发器 disable trigger all on all server  --5.7启用服务器上所有的服务器级别触发器 enable trigger all on all server  --5.8删除dml触发器 drop trigger dbo.t_after  --5.9删除ddl数据库级别触发器 drop trigger wc on database  --5.10删除ddl服务器级别触发器 drop trigger gyy_server on all server   --6.设置触发器触发的次序 create trigger dbo.tt_1 on dbo.t after insert as  print 'dbo.tt_1' go   create trigger dbo.tt_2 on dbo.t after insert as  print 'dbo.tt_2' go   create trigger dbo.tt_3 on dbo.t after insert as  print 'dbo.tt_3' go   --设置触发器触发的次序 exec sp_settriggerorder  	@triggername = 'tt_1', --触发器名称  	@order ='first',       --指定的次序 	@stmttype = 'insert'  --触发器类型  exec sp_settriggerorder 	@triggername = 'tt_2', 	@order = 'last', 	@stmttype = 'insert' 	 --触发多个触发器 insert into dbo.t values(10,'w','www')  /*====================================== 输出消息:  		dbo.tt_1 		dbo.tt_3 		dbo.tt_2 ========================================*/

 

如果有10个表,需要union all这10个表的数据来查询,那么通过建立一个视图,然后要对视图进行插入操作,那么必须有几个必要的条件:

1.每个表都有主键

2.每个表必须有check约束,来指定任何一条数据,到底要插入到那个表中。

 

下面为ddl触发器的实例:

--2.1在master数据库中建立服务器级别跟踪表 use master go  create table server_eventdata 	(eventdata xml,      principal_user nvarchar(100),      login_user nvarchar(100)     ) go     /* select * from sys.trigger_event_types where type_name like '%grant%' or       type_name like '%deny%' or       type_name like '%revoke%' */            --2.2建立服务器级别触发器  create trigger gyy_server on all server for GRANT_SERVER,     DENY_SERVER,     REVOKE_SERVER,     GRANT_DATABASE,     DENY_DATABASE,     REVOKE_DATABASE as  insert into server_eventdata select EVENTDATA(),USER,SUSER_NAME() go   --2.3 create database wc go  use wc go  create table dbo.wc_table(v int)  insert into dbo.wc_table values(1) go   use wc go  grant select on wc.dbo.wc_table to public  go  --查看记录的事件 select EVENTDATA,        eventdata.value('(/EVENT_INSTANCE/EventType)[1]','nvarchar(100)') as '事件类型',        eventdata.value('(/EVENT_INSTANCE/TSQLCommand)[1]','nvarchar(100)') as 'sql授权语句',                '登录名' + eventdata.value('(/EVENT_INSTANCE/LoginName)[1]','nvarchar(100)') +         '用户名' + eventdata.value('(/EVENT_INSTANCE/UserName)[1]','nvarchar(100)') + ',授予者'+        eventdata.value('(/EVENT_INSTANCE/Grantor)[1]','nvarchar(100)') + ' 把类型为:' +        eventdata.value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(100)') + '的对象' +        eventdata.value('(/EVENT_INSTANCE/DatabaseName)[1]','nvarchar(100)') + '.' +        eventdata.value('(/EVENT_INSTANCE/SchemaName)[1]','nvarchar(100)') + '.' +        eventdata.value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(100)') + '的' +        eventdata.value('(/EVENT_INSTANCE/Permissions/Permission)[1]','nvarchar(100)') +'权限授予给' +                eventdata.value('(/EVENT_INSTANCE/Grantees)[1]','nvarchar(100)')                                 from master.dbo.server_eventdata t

下面是一段引用自邹建的代码,通过链接服务器+触发器,实现数据同步的代码,很有借鉴作用:

/*     作者:邹建     */         /*--同步两个数据库的示例         有数据     srv1.库名..author有字段:id,name,phone,     srv2.库名..author有字段:id,name,telphone,adress         要求:     srv1.库名..author增加记录则srv1.库名..author记录增加     srv1.库名..author的phone字段更新,则srv1.库名..author对应字段telphone更新     --*/         --大致的处理步骤     --1.在   srv1   上创建连接服务器,以便在   srv1   中操作   srv2,实现同步     exec   sp_addlinkedserver     'srv2','','SQLOLEDB','srv2的sql实例名或ip'     exec   sp_addlinkedsrvlogin   'srv2','false',null,'用户名','密码'     go         --2.在   srv1   和   srv2   这两台电脑中,启动   msdtc(分布式事务处理服务),并且设置为自动启动     我的电脑--控制面板--管理工具--服务--右键   Distributed   Transaction   Coordinator--属性--启动--并将启动类型设置为自动启动     go             --3.实现同步处理         --a.在srv1..author中创建触发器,实现数据即时同步     --新增同步     create   trigger   tr_insert_author   on   author     for   insert     as     set   xact_abort   on     insert   srv2.库名.dbo.author(id,name,telphone)     select   id,name,telphone   from   inserted     go         --修改同步     create   trigger   tr_update_author   on   author     for   update     as     set   xact_abort   on     update   b   set   name=i.name,telphone=i.telphone     from   srv2.库名.dbo.author   b,inserted   i     where   b.id=i.id     go         --删除同步     create   trigger   tr_delete_author   on   author     for   delete     as     set   xact_abort   on     delete   b       from   srv2.库名.dbo.author   b,deleted   d     where   b.id=d.id     go