我有一个场景需要类似.NET's try-catch-finally block.
在我尝试的时候,我会CREATE a #temp table
,INSERT
数据给它&根据{{1}}处理其他数据集。
在#temp
然后CATCH
。
是否可以RAISERROR
阻止FINALLY
?
以下是伪代码:
DROP #temp
答案 0 :(得分:23)
虽然与FINALLY不完全相同,但Try-Catch的T-SQL版本确实允许在END CATCH语句结束后可以发生Try和Catch块之后需要执行的代码。 使用问题代码作为示例:
BEGIN TRY
CREATE TABLE #temp
(
--columns
)
--Process data with other data sets
END TRY
BEGIN CATCH
EXECUTE usp_getErrorMessage
END CATCH;
IF OBJECT_ID('tempdb..#temp') IS NOT NULL -- Check for table existence
DROP TABLE #temp;
无论Try还是Catch执行,DROP TABLE命令都会执行。 请参阅:BOL Try...Catch
答案 1 :(得分:11)
您可以只声明一个表变量(在查询结束时会自动消失),而不是创建表。
BEGIN TRY
DECLARE @temp TABLE
(
--columns
)
--do stuff
END TRY
BEGIN CATCH
--do other stuff
END CATCH
答案 2 :(得分:6)
没有等效的FINALLY
替代方案可能是表变量,但不完全相同,必须根据具体情况进行评估。
有一个SO question详细信息非常有用,可以做出明智的选择。
使用表变量,您不需要像使用临时表一样进行清理
答案 3 :(得分:0)
“ FINALLY”在功能上通常与(但不总是)与在TRY / CATCH(没有正式的“ FINALLY”块)之后跟随“ final”代码相同。如果情况不同,则TRY / CATCH块中的某些内容可能导致执行结束,例如return语句。
例如,我使用的一种模式是打开一个游标,然后将使用游标的代码放在TRY块中,然后在TRY / CATCH块之后关闭/释放游标。如果这些块不会退出正在执行的代码,这将很好地工作。但是,如果TRY CATCH块确实执行了RETURN(听起来像是个坏主意),如果被 FINALLY块执行了,则将会被执行,但是按照T-SQL的要求,将“最终”代码放在TRY / CATCH之后,如果这些代码块导致执行结束,则将调用最终代码不会,可能会导致状态不一致
因此,虽然通常您可以将代码放在TRY / CATCH之后,但是如果这些块中的任何内容可以终止而不会进入清除代码,将是一个问题。
答案 4 :(得分:0)
SQL连接结束时,本地临时表(例如“ #Temp”)会自动删除。最好还是包含一个明确的DROP命令,但是如果不执行该命令,该表仍将被删除。
如果必须确保DROP尽快执行,则必须在CATCH子句中重复DROP命令,因为没有FINALLY: -创建临时表; 开始尝试 -使用临时表; -删除临时表; 结束尝试 开始比赛 -删除临时表; 扔; -重新抛出错误 结束观看
表变量是一种替代方法:当变量超出范围时将其删除。但是,表变量不支持统计信息,因此,如果表变量很大并且在多个查询中使用,则其性能可能不如临时表。
答案 5 :(得分:0)
使用自定义错误号表示没有真正的错误,只是最终代码?
-- create temp table;
BEGIN TRY
-- use temp table;
THROW 50555;
END TRY
BEGIN CATCH
-- drop temp table;
IF ERROR_NUMBER() <> 50555
THROW; -- rethrow the error
END CATCH
答案 6 :(得分:0)
这种情况下的正确答案是@Dave Bennett 提出的答案;在 TRY/CATCH 块之后检查表的存在并删除它。
但是,如果您从 CATCH 中引发异常并且需要进行一些“最终”类型处理怎么办?
会不会像在 CATCH 中设置一个变量并在您掉出 CATCH 后检查它一样简单?
DECLARE @is_error BIT = 0;
BEGIN TRY
--Process data with other data sets
END TRY
BEGIN CATCH
-- Your exception handling code here
SET @is_error = 1;
END CATCH
-- Your "FINALLY" code here.
-- Then Check if you need to RAISERROR
IF @is_error = 0
BEGIN
-- Your success code
END
ELSE
BEGIN
-- Your fail code
-- RAISERROR
END;