最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了。

所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路。

本篇是触发器专题,有很多触发器的问题。


1、关于触发器中回滚的问题。


在官方文档http://technet.microsoft.com/zh-cn/library/ms181299.aspx中“互操作性”段落中有这么一句:
    触发器继续执行 ROLLBACK 语句之后的所有其余语句。 如果这些语句中的任意语句修改数据,则不回滚这些修改。 执行其余的语句不会激发嵌套触发器。
其中“执行其余的语句不会激发嵌套触发器”,是否意味着在回滚操作后面的语句如果继续执行的话,后面语句触发的触发器就不会执行了。比如后面的语句有针对一个表的update操作,而这张表又有update的触发器,这个时候update会执行成功,但触发器不会执行?


但是很奇怪,我做了一个实验,发现,即使是嵌套触发器,也能够被触发,和微软文档上说的不一样。

从下面的insert时的输出,可以看出,在触发器中rollback之后的语句,是可以执行的,另外,update另一个表的操作也执行成功,并且触发了触发器。


--drop table t1 --drop table t2  create table t1(id int) create table t2(id int)  insert into t2 values(100) go  create trigger dbo.trigger_t1 on t1 for insert as  rollback;  select '这是rollback之后的语句,这里能执行'  update t2 set id = 1; go    create trigger dbo.trigger_t2 on t2 for update as  select '这是t2的update触发器,这里能执行'  go   --插入数据 insert into t1 values(1) /* 这是rollback之后的语句,这里能执行  这是t2的update触发器,这里能执行  消息 3609,级别 16,状态 1,第 3 行 事务在触发器中结束。批处理已中止。 */   --没有记录 select * from t1   select * from t2 /* id 1 */ 


2、触发器的错误处理

http://bbs.csdn.net/topics/390637035


我在A表写了个触发器 插入后执行,是向B表插入一条记录

USE [test] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER TRIGGER [dbo].[tba_delete]     ON  [dbo].[tba]     AFTER INSERT AS  BEGIN 	SET NOCOUNT ON; 	insert into test.dbo.tbb(title,info) values('title','info'); END 

在A表插入数据后正常。当我把 语言改为:

insert into test.dbo.tbb(id,title,info) values(1,'title','info'); 

故意出错。问题出现了,当触发器内的语句出错,向A表插入的数据就不能成功插入。
向朋友们求教个问题。我要如何把触发器中的出错信息记录下来?或者在什么地方可以查看到触发器执行时是否出错了,及查看错误的信息?


我的解法:

USE [test] GO  SET ANSI_NULLS ON GO  SET QUOTED_IDENTIFIER ON GO   create table [tba](title varchar(20),info varchar(20))  create table tbb(title varchar(20),info varchar(20))   --创建一个存放错误信息的表 create table tb_error_message ( obj_name nvarchar(30), obj_type nvarchar(15), err_msg nvarchar(100), err_date datetime ) go  drop trigger tba_delete go  create TRIGGER [dbo].[tba_delete]     ON  [dbo].[tba]     AFTER INSERT AS  BEGIN 	SET NOCOUNT ON; 	 	begin try 	--这里模拟插入title列的数据长度,超过了定义时的20 	insert into test.dbo.tbb(title,info) values('title1111111111111111111','info'); 	end try 	 	begin catch 	--错误了就回滚     rollback;	 	insert into tb_error_message 	values('tba_delete','trigger',error_message(),getdate())             	end catch 	 END go  insert into tba values('11','11') /* 消息 3930,级别 16,状态 1,过程 tba_delete,第 16 行 当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务。 语句已终止。 */   --查询出错的信息 select * from tb_error_message /* obj_name	obj_type	err_msg	err_date tba_delete	trigger	将截断字符串或二进制数据。	2013-11-08 12:32:16.750 */

3、忽略触发器中的错误

http://bbs.csdn.net/topics/390623172

我的情况是这样的: 当向A表插入数据时,需要向某用户发送信息通知,由于插入数据方是第三方软件做的,我控件不了,所以我在A表加个触发器来实现,现在问题是发送信息这里的错误是可以忽略的,就是说假如发送失败不影响数据的插入,请问我在触发器里如何忽略错误,让事务继续执行.

我的思路是:

--先保存一个事务点 SAVEPOINT xxx   begin try      --或者是调用存储过程,或者就直接写代码    exec 发送信息的存储过程       end try   begin catch     select '执行失败'     --一旦出错,只是回滚到上面的事务点,继续执行   ROLLBACK [WORK] TO SAVEPOINT xxx end catch    --其他代码