[英]SQL Server TRY CATCH FINALLY
我有一個場景,我需要類似於.NET's try-catch-finally block.
在我的嘗試中,我將CREATE a #temp table
,向其中INSERT
數據並基於#temp
處理其他數據集。
在CATCH
然后是RAISERROR
。 是否可以有一個FINALLY
塊來DROP #temp
? 下面是偽代碼:
BEGIN TRY
CREATE TABLE #temp
(
--columns
)
--Process data with other data sets
END TRY
BEGIN CATCH
EXECUTE usp_getErrorMessage
END CATCH
BEGIN FINALLY
DROP TABLE #temp
END FINALLY
雖然與 FINALLY 不完全相同,但 Try-Catch 的 T-SQL 版本確實允許需要在 Try 和 Catch 塊之后執行的代碼可以在 END 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
您可以只聲明一個表變量(當查詢結束時它會自動消失),而不是創建一個表。
BEGIN TRY
DECLARE @temp TABLE
(
--columns
)
--do stuff
END TRY
BEGIN CATCH
--do other stuff
END CATCH
沒有FINALLY
等價物。
另一種可能是表變量,但並不完全相同,必須根據具體情況進行評估。
有一個SO question with details 對於做出明智的選擇非常有用。
使用表變量,您不需要像使用臨時表一樣進行清理
“FINALLY”通常(但不總是)在功能上與 TRY/CATCH 后面的“final”代碼相同(沒有正式的“FINALLY”塊)。 不同之處在於 TRY/CATCH 塊中的某些內容可能導致執行結束,例如 return 語句。
例如,我使用的一種模式是打開一個游標,然后在 TRY 塊中使用游標代碼,在 TRY/CATCH 塊之后關閉/解除分配游標。 如果塊不會退出正在執行的代碼,這可以正常工作。 但是,如果try catch塊呢,例如,RETURN(它像一個壞主意的聲音),如果有一個finally塊,它會得到執行,但與“最終”的代碼放在try / catch語句之后,如T-SQL 要求,如果這些代碼塊導致執行結束,則不會調用最終代碼,從而可能留下不一致的狀態。
因此,雖然通常您可以將代碼放在 TRY/CATCH 之后,但如果這些塊中的任何內容都可以終止而不會落入清理代碼,那將是一個問題。
當 SQL 連接結束時,本地臨時表(例如,“#Temp”)會自動刪除。 無論如何,包含顯式DROP
命令是一種很好的做法,但如果它不執行,該表仍將被刪除。
如果必須確保DROP
盡快執行,則必須在CATCH
子句中重復DROP
命令,因為沒有FINALLY
:
-- create temp table;
BEGIN TRY
-- use temp table;
-- drop temp table;
END TRY
BEGIN CATCH
-- drop temp table;
THROW; -- rethrow the error
END CATCH
表變量是另一種選擇:當變量超出范圍時,它們會被刪除。 但是,表變量不支持統計,因此如果表變量很大並且用於多個查詢,它的性能可能不如臨時表。
使用自定義錯誤編號來表示沒有真正的錯誤,只是最終代碼?
-- 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
在這種情況下,正確答案是@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;
使用 T-SQL,放置在TRY-CATCH
塊之后的代碼將被執行。 所以這個問題的答案只是在END CATCH
之后添加一個DROP TABLE IF EXISTS #temp
,如下所示:
BEGIN TRY
CREATE TABLE #temp(
--columns
)
--Process data with other data sets
END TRY
BEGIN CATCH
EXECUTE usp_getErrorMessage
END CATCH
-- Anything under this line will execute regardless of if the code reached the CATCH block or not.
DROP TABLE IF EXISTS #temp; -- Works in SQL Server 2016+, for older versions see here: https://stackoverflow.com/a/31171650/15596537
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.