簡體   English   中英

SQL Server 最終嘗試捕獲

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM