使用GOTO& SQL事务中SQL中的标签

时间:2016-09-16 16:56:51

标签: sql sql-server

我有一个长期运行的脚本,我希望将其包含在最多可能包含 100+个交易的交易中。

我想实现一些错误处理和重用代码。我在考虑使用标签和GOTO语句。

BEGIN TRY
BEGIN TRANSACTION abc
    --DO SOMETHING
    COMMIT TRANSACTION abc;
END TRY
BEGIN CATCH
    GOTO ERROR_OUT
END CATCH

ERROR_OUT:  
       SELECT ERROR_MESSAGE() [ErrorMessage];  
       ROLLBACK;    

使用多笔交易时应该做些什么?

在我强制出错的简单测试中,我注意到ERROR_MESSGE()SELECT语句没有返回结果。

使用标签时,有没有办法让select语句返回结果?

2 个答案:

答案 0 :(得分:4)

Declare @Table table (Num float,Den float,Pct float)
Insert into @Table values (25,100,0),(50,0,0)

BEGIN TRY
BEGIN TRANSACTION abc
    -- Force a Divide by Zero on 2nd record
    Update @Table Set Pct=Num/Den
    COMMIT TRANSACTION abc;
    Select * from @Table
    GOTO CLEAN_OUT
END TRY
BEGIN CATCH
    Declare @Error varchar(max)=Error_Message()
    GOTO ERROR_OUT
END CATCH

ERROR_OUT: 
    ROLLBACK;
    Select ErrorMessage=@Error 
    Select * From @Table

CLEAN_OUT:
Go

返回

ErrorMessage
Divide by zero error encountered.

Num Den Pct
25  100 0
50  0   0

然后用(50,125,0)

尝试

答案 1 :(得分:3)

评论太长了。

一般情况下,不鼓励程序员使用goto。原因是它是一个控制流原语,并且存在许多常用案例的替代方案:if / then / elsewhile,等等。

但是,在某些情况下goto非常有用。错误处理就是其中之一。如果你谷歌“转到错误处理”,不难找到thisthis等解释(虽然对于C,我认为推理非常相似)。

我经常在SQL Server存储过程中使用goto来实现此目的。虽然在我的情况下,目标是在离开存储过程时实现适当的审计和错误处理。

您的用例似乎是一个很好的例子,goto是一种非常合理的代码块编码方式。我发现“数百个交易”部分更值得怀疑。就个人而言,我喜欢明确处理交易的时间和地点,因此我更有可能写下:

. . .
begin catch:
    rollback ;
    goto error_out;
end;

也就是说,要显式回滚事务开始的“旁边”事务,而不是在某个远程代码块中执行该操作。