我有一个在insert-exec块中调用的存储过程:
insert into @t
exec('test')
如何处理存储过程中生成的异常并仍继续处理?
以下代码说明了该问题。我想做的是根据内部exec()
调用的成功或失败返回0或-1 :
alter procedure test -- or create
as
begin try
declare @retval int;
-- This code assumes that PrintMax exists already so this generates an error
exec('create procedure PrintMax as begin print ''hello world'' end;')
set @retval = 0;
select @retval;
return(@retval);
end try
begin catch
-- if @@TRANCOUNT > 0 commit;
print ERROR_MESSAGE();
set @retval = -1;
select @retval;
return(@retval);
end catch;
go
declare @t table (i int);
insert into @t
exec('test');
select *
from @t;
我的问题是return(-1)
。成功的道路很好。
如果我在存储过程中遗漏了try / catch块,则会引发错误并且插入失败。但是,我想做的是处理错误并返回一个不错的值。
代码按原样返回消息:
Msg 3930, Level 16, State 1, Line 6
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
这可能是我遇到的最糟糕的错误消息。这似乎真的意味着“您没有在嵌套事务中处理错误”。
如果输入if @@TRANCOUNT > 0
,则会收到以下消息:
Msg 3916, Level 16, State 0, Procedure gordontest, Line 7
Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.
我试过开始/提交事务语句,但似乎没有任何效果。
因此,如何让我的存储过程在不中断整个事务的情况下处理错误?
编辑以响应Martin:
实际的调用代码是:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
声明@retval int; exec @retval ='+ @ query +'; 选择@retval');
select @retval = retval from @RetvalTable;
@query
存储过程调用在哪里。目的是从存储过程中获取返回值。如果没有insert
(或者更具体地说,没有开始交易)这是可能的,那将很棒。
我通常不能修改存储过程以将值存储在表中,因为它们太多了。 其中之一失败了,我可以进行修改。我目前最好的解决方案是:
if (@StoredProcedure = 'sp_rep__post') -- causing me a problem
begin
exec @retval = sp_rep__post;
end;
else
begin
-- the code I'm using now
end;
select @retval; return @retval
是最后。如果您知道从动态存储过程调用中获取返回值的另一种方法,我很想知道。
DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
工作良好。