Gor*_*off 11 sql-server-2008 sql-server
我有一个在 insert-exec 块中调用的存储过程:
insert into @t
exec('test')
Run Code Online (Sandbox Code Playgroud)
如何处理存储过程中生成的异常并继续处理?
下面的代码说明了这个问题。我想要做的是根据内部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;
Run Code Online (Sandbox Code Playgroud)
我的问题是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.
Run Code Online (Sandbox Code Playgroud)
这可能是我遇到的最糟糕的错误消息。这似乎真的意味着“您没有处理嵌套事务中的错误”。
如果我输入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.
Run Code Online (Sandbox Code Playgroud)
我试过使用开始/提交事务语句,但似乎没有任何效果。
那么,如何在不中止整个事务的情况下让我的存储过程处理错误?
编辑回应马丁:
实际调用代码为:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
Run Code Online (Sandbox Code Playgroud)
声明@retval int; exec @retval = '+@query+'; 选择@retval');
select @retval = retval from @RetvalTable;
Run Code Online (Sandbox Code Playgroud)
@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;
Run Code Online (Sandbox Code Playgroud)
Mar*_*ith 14
语句EXEC部分中的错误INSERT-EXEC使您的交易处于注定失败的状态。
如果PRINT出XACT_STATE()在CATCH它被设置为块-1。
并非所有错误都会将状态设置为此。以下检查约束错误通过 catch 块并INSERT成功。
ALTER PROCEDURE test -- or create
AS
BEGIN try
DECLARE @retval INT;
DECLARE @t TABLE(x INT CHECK (x = 0))
INSERT INTO @t
VALUES (1)
SET @retval = 0;
SELECT @retval;
RETURN( @retval );
END try
BEGIN catch
PRINT XACT_STATE()
PRINT ERROR_MESSAGE();
SET @retval = -1;
SELECT @retval;
RETURN( @retval );
END catch;
Run Code Online (Sandbox Code Playgroud)
将此添加到CATCH块
IF (XACT_STATE()) = -1
BEGIN
ROLLBACK TRANSACTION;
END;
Run Code Online (Sandbox Code Playgroud)
没有帮助。它给出了错误
不能在 INSERT-EXEC 语句中使用 ROLLBACK 语句。
一旦发生此类错误,我认为没有任何方法可以从这种错误中恢复。对于您的特定用例,您INSERT ... EXEC无论如何都不需要。您可以将返回值分配给标量变量,然后将其插入到单独的语句中。
DECLARE @RC INT;
EXEC sp_executesql
N'EXEC @RC = test',
N'@RC INT OUTPUT',
@RC = @RC OUTPUT;
INSERT INTO @t
VALUES (@RC)
Run Code Online (Sandbox Code Playgroud)
或者当然您可以重构被调用的存储过程,以便它根本不会引发该错误。
DECLARE @RetVal INT = -1
IF OBJECT_ID('PrintMax', 'P') IS NULL
BEGIN
EXEC('create procedure PrintMax as begin print ''hello world'' end;')
SET @RetVal = 0
END
SELECT @RetVal;
RETURN( @RetVal );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30437 次 |
| 最近记录: |