TRY...CATCH (Transact-SQL)
適用於:SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體 Azure Synapse Analytics Analytics Platform System (PDW) Microsoft Fabric 的 SQL 端點分析 Microsoft Fabric 的倉儲
實作 Transact-SQL 的錯誤處理,類似於 C# 和 Visual C++ 語言中的例外狀況處理。 Transact-SQL 語句的群組可以封入區塊中 TRY
。 如果區塊中 TRY
發生錯誤,控件通常會傳遞至區塊中所 CATCH
封入的另一組語句。
語法
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
引數
sql_statement
任何 Transact-SQL 語句。
statement_block
批次中或以區塊括住 BEGIN...END
的任何 Transact-SQL 語句群組。
備註
建 TRY...CATCH
構會攔截所有嚴重性高於 10 但未關閉資料庫連線的執行錯誤。
TRY
區塊後面必須緊接著相關聯的CATCH
區塊。 包含和 BEGIN CATCH
語句之間的END TRY
任何其他語句會產生語法錯誤。
TRY...CATCH
建構無法跨越多個批次。 TRY...CATCH
建構無法跨越 Transact-SQL 語句的多個區塊。 例如,建構無法跨越 Transact-SQL 語句的兩BEGIN...END
個TRY...CATCH
區塊,而且無法跨越IF...ELSE
建構。
如果區塊中最後一個 TRY
語句 TRY
完成時,區塊中的程式代碼中沒有任何錯誤,控件就會在相關聯的 END CATCH
語句之後立即傳遞至 語句。
如果區塊中 TRY
含有錯誤,控件會傳遞至相關聯 CATCH
區塊中的第一個語句。 當區塊中的 CATCH
程式代碼完成時,控件會緊接在語句之後 END CATCH
傳遞至 語句。
注意
END CATCH
如果語句是預存程式或觸發程式中的最後一個語句,控件會傳回至呼叫預存程式或引發觸發程式的語句。
區塊所 CATCH
截獲的錯誤不會傳回給呼叫的應用程式。 如果錯誤資訊的任何部分必須傳回給應用程式,區塊中的CATCH
程式代碼必須使用結果集或 RAISERROR
和 PRINT
語句等SELECT
機制來執行此動作。
TRY...CATCH
建構可以是巢狀結構。 TRY
區塊或CATCH
區塊可以包含巢狀TRY...CATCH
建構。 例如, CATCH
區塊可以包含內嵌 TRY...CATCH
建構來處理程序代碼所遇到的 CATCH
錯誤。
區塊中 CATCH
遇到的錯誤會被視為在其他地方產生的錯誤。 CATCH
如果區塊包含巢狀TRY...CATCH
建構,巢狀TRY
區塊中的任何錯誤都會將控制權傳遞至巢狀CATCH
區塊。 如果沒有巢狀 TRY...CATCH
建構,錯誤會傳回給呼叫端。
TRY...CATCH
建構會從預存程式或區塊中的 TRY
程式代碼所執行的觸發程式攔截未處理的錯誤。 或者,預存程式或觸發程式可以包含自己的 TRY...CATCH
建構,以處理其程式代碼所產生的錯誤。 例如,當 TRY
區塊執行預存程式,並在預存程式中發生錯誤時,可以使用下列方式處理錯誤:
如果預存程式未包含自己的
TRY...CATCH
建構,則錯誤會將控件CATCH
傳回與包含EXECUTE
語句之TRY
區塊相關聯的區塊。如果預存程式包含
TRY...CATCH
建構,錯誤會將控件傳輸至CATCH
預存程式中的 區塊。 當區塊程序CATCH
代碼完成時,控件會緊接在呼叫預存程式的語句之後EXECUTE
傳回語句。
GOTO
語句無法用來輸入 TRY
或 CATCH
區塊。 GOTO
語句可用來跳至相同 TRY
或 CATCH
區塊內的標籤,或離開 TRY
或 CATCH
區塊。
建 TRY...CATCH
構不能用於使用者定義函式。
擷取錯誤資訊
在區塊的範圍內 CATCH
,下列系統函式可用來取得導致 CATCH
區塊執行之錯誤的相關信息:
函式 | 描述 |
---|---|
ERROR_NUMBER | 傳回錯誤的數目。 |
ERROR_SEVERITY | 傳回嚴重性。 |
ERROR_STATE | 傳回錯誤狀態號碼。 |
ERROR_PROCEDURE | 傳回發生錯誤的預存程式或觸發程式名稱。 |
ERROR_LINE | 傳回造成錯誤的例程內的行號。 |
ERROR_MESSAGE | 傳回錯誤訊息的完整文字。 文字包括提供給任何可替代參數的值,例如,長度、物件名稱或次數。 |
這些函式會在區塊範圍CATCH
之外呼叫它們時傳回 NULL
。 您可以從區塊範圍內 CATCH
的任何位置使用這些函式來擷取錯誤資訊。 例如,下列指令碼顯示包含錯誤處理函數的預存程序。 在 CATCH
建構的 TRY...CATCH
區塊中,會呼叫預存程序,並傳回錯誤的相關資訊。
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID('usp_GetErrorInfo', 'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
GO
BEGIN TRY
-- Generate divide-by-zero error.
SELECT 1 / 0;
END TRY
BEGIN CATCH
-- Execute error retrieval routine.
EXECUTE usp_GetErrorInfo;
END CATCH;
函式ERROR_*
也會在CATCH
原生編譯預存程式內的 區塊中運作。
TRY 未受影響的錯誤...CATCH 建構
TRY...CATCH
建構不會設陷下列條件:
嚴重性為 10 或以下的警告或參考訊息。
嚴重性為 20 或以上的錯誤,會停止工作階段的 SQL Server 資料庫引擎工作處理。 如果發生嚴重性為 20 或更新版本且資料庫連線未中斷的錯誤,
TRY...CATCH
請處理錯誤。用戶端中斷要求或中斷用戶端連接之類的注意事項。
當系統管理員使用
KILL
語句結束會話時。
當發生於與建構相同的執行TRY...CATCH
層級時,區塊不會處理CATCH
下列類型的錯誤:
造成無法執行批次的編譯錯誤,如語法錯誤。
在陳述式層級重新編譯期間發生的錯誤,例如在編譯之後,因延遲的名稱解析所發生的物件名稱解析錯誤。
物件名稱解析錯誤
這些錯誤會傳回執行批次、預存程序或觸發程序的層級。
如果在編譯或語句層級重新編譯期間發生錯誤,且執行層級較低(例如,在區塊內TRY
執行sp_executesql
或使用者定義預存程式時),則錯誤會在低於建構的層級TRY...CATCH
發生,且將由相關聯的CATCH
區塊處理。
下列範例示範 語句所產生的SELECT
物件名稱解析錯誤不會由 TRY...CATCH
建構攔截,但在預存程式內執行相同SELECT
語句時,區塊會攔截CATCH
。
BEGIN TRY
-- Table does not exist; object name resolution
-- error not caught.
SELECT *
FROM NonexistentTable;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH
錯誤不會攔截,而且控制權會從建構傳出 TRY...CATCH
至下一個較高層級。
在 SELECT
預存程式內執行 語句會導致錯誤發生在低於 區塊的 TRY
層級。 錯誤是由 TRY...CATCH
建構所處理。
-- Verify that the stored procedure does not exist.
IF OBJECT_ID(N'usp_ExampleProc', N'P') IS NOT NULL
DROP PROCEDURE usp_ExampleProc;
GO
-- Create a stored procedure that will cause an
-- object resolution error.
CREATE PROCEDURE usp_ExampleProc
AS
SELECT *
FROM NonexistentTable;
GO
BEGIN TRY
EXECUTE usp_ExampleProc;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
無法認可的交易和XACT_STATE
如果區塊中 TRY
產生的錯誤導致目前交易的狀態失效,交易就會分類為無法認可的交易。 通常結束區塊外部 TRY
交易的錯誤會導致交易在區塊內 TRY
發生錯誤時進入無法認可的狀態。 無法認可的交易只能執行讀取作業或 ROLLBACK TRANSACTION
。 交易無法執行任何會產生寫入作業或 COMMIT TRANSACTION
的 Transact-SQL 語句。 如果交易已分類為無法認可的交易,則函 XACT_STATE
式會傳回的值 -1
。 當批次完成後,資料庫引擎會回復所有使用中的無法認可交易。 如果交易進入無法認可狀態時未傳送任何錯誤訊息,當批次完成時,就會將錯誤訊息傳送至客戶端應用程式。 這表示偵測到無法認可的交易,並且需要回復它。
如需無法認可交易和函 XACT_STATE
式的詳細資訊,請參閱 XACT_STATE。
範例
A. 使用 TRY...CATCH
下列範例顯示將會產生除以零之錯誤的 SELECT
陳述式。 這個錯誤會使執行動作跳到相關聯的 CATCH
區塊。
BEGIN TRY
-- Generate a divide-by-zero error.
SELECT 1 / 0;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
B. 使用 TRY...交易中的 CATCH
下列範例顯示 TRY...CATCH
區塊在交易內運作的方式。 TRY
區塊內的陳述式產生條件約束違規錯誤。
BEGIN TRANSACTION;
BEGIN TRY
-- Generate a constraint violation error.
DELETE
FROM Production.Product
WHERE ProductID = 980;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF @@TRANCOUNT > 0
COMMIT TRANSACTION;
GO
C. 使用 TRY...CATCH 與 XACT_STATE
下列範例顯示如何利用 TRY...CATCH
建構來處理交易內所發生的錯誤。 XACT_STATE
函數會判斷是否應該認可或回復交易。 在此範例中,SET XACT_ABORT
是 ON
。 當發生條件約束違規錯誤時,會使交易成為無法認可。
-- Check to see whether this stored procedure exists.
IF OBJECT_ID(N'usp_GetErrorInfo', N'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_LINE() AS ErrorLine,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_MESSAGE() AS ErrorMessage;
GO
-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- A FOREIGN KEY constraint exists on this table. This
-- statement will generate a constraint violation error.
DELETE
FROM Production.Product
WHERE ProductID = 980;
-- If the DELETE statement succeeds, commit the transaction.
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Execute error retrieval routine.
EXECUTE usp_GetErrorInfo;
-- Test XACT_STATE:
-- If 1, the transaction is committable.
-- If -1, the transaction is uncommittable and should
-- be rolled back.
-- XACT_STATE = 0 means that there is no transaction and
-- a commit or rollback operation would generate an error.
-- Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test whether the transaction is committable.
-- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
IF (XACT_STATE()) = 1
BEGIN
PRINT N'The transaction is committable. Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH;
GO
相關內容
- THROW (Transact-SQL)
- 資料庫引擎 錯誤嚴重性
- ERROR_LINE (Transact-SQL)
- ERROR_MESSAGE (Transact-SQL)
- ERROR_NUMBER (Transact-SQL)
- ERROR_PROCEDURE (Transact-SQL)
- ERROR_SEVERITY (Transact-SQL)
- ERROR_STATE (Transact-SQL)
- RAISERROR (Transact-SQL)
- @@ERROR (Transact-SQL)
- GOTO (Transact-SQL)
- BEGIN...END (Transact-SQL)
- XACT_STATE (Transact-SQL)
- SET XACT_ABORT (Transact-SQL)