適用於:SQL Server
Azure SQL 資料庫
Azure SQL 受控執行個體
Azure Synapse Analytics
分析平台系統(PDW)
Microsoft Fabric 中的 SQL 分析端點
Microsoft Fabric 中的倉儲
Microsoft Fabric 中的 SQL 資料庫
實作 Transact-SQL 的錯誤處理,類似於 C# 和 Visual C++ 語言中的例外狀況處理。 Transact-SQL 語句的群組可以封入區塊中 TRY 。 如果區塊中 TRY 發生錯誤,控件通常會傳遞至區塊中所 CATCH 封入的另一組語句。
Syntax
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
Arguments
sql_statement
任何 Transact-SQL 語句。
statement_block
批次中或以區塊括住 BEGIN...END 的任何 Transact-SQL 語句群組。
Remarks
建 TRY...CATCH 構會攔截所有嚴重性高於 10 但未關閉資料庫連線的執行錯誤。
TRY區塊後面必須緊接著相關聯的CATCH區塊。 包含和 END TRY 語句之間的BEGIN CATCH任何其他語句會產生語法錯誤。
TRY...CATCH建構無法跨越多個批次。
TRY...CATCH建構無法跨越 Transact-SQL 語句的多個區塊。 例如,建構無法跨越 Transact-SQL 語句的兩TRY...CATCH個BEGIN...END區塊,而且無法跨越IF...ELSE建構。
如果區塊中最後一個 TRY 語句 TRY 完成時,區塊中的程式代碼中沒有任何錯誤,控件就會在相關聯的 END CATCH 語句之後立即傳遞至 語句。
如果區塊中 TRY 含有錯誤,控件會傳遞至相關聯 CATCH 區塊中的第一個語句。 當區塊中的 CATCH 程式代碼完成時,控件會緊接在語句之後 END CATCH 傳遞至 語句。
Note
END CATCH如果語句是預存程式或觸發程式中的最後一個語句,控件會傳回至呼叫預存程式或引發觸發程式的語句。
區塊所 CATCH 截獲的錯誤不會傳回給呼叫的應用程式。 如果錯誤資訊的任何部分必須傳回給應用程式,區塊中的CATCH程式代碼必須使用結果集或 SELECT 和 RAISERROR 語句等PRINT機制來執行此動作。
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傳回與包含TRY語句之EXECUTE區塊相關聯的區塊。如果預存程式包含
TRY...CATCH建構,錯誤會將控件傳輸至CATCH預存程式中的 區塊。 當區塊程序CATCH代碼完成時,控件會緊接在呼叫預存程式的語句之後EXECUTE傳回語句。
GOTO 語句無法用來輸入 TRY 或 CATCH 區塊。
GOTO 語句可用來跳至相同 TRY 或 CATCH 區塊內的標籤,或離開 TRY 或 CATCH 區塊。
建 TRY...CATCH 構不能用於使用者定義函式。
擷取錯誤資訊
在區塊的範圍內 CATCH ,下列系統函式可用來取得導致 CATCH 區塊執行之錯誤的相關信息:
| Function | Description |
|---|---|
| ERROR_NUMBER | 傳回錯誤的數目。 |
| ERROR_SEVERITY | 傳回嚴重性。 |
| ERROR_STATE | 傳回錯誤狀態號碼。 |
| ERROR_PROCEDURE | 傳回發生錯誤的預存程式或觸發程式名稱。 |
| ERROR_LINE | 傳回造成錯誤的例程內的行號。 |
| ERROR_MESSAGE | 傳回錯誤訊息的完整文字。 文字包括提供給任何可替代參數的值,例如,長度、物件名稱或次數。 |
這些函式會在區塊範圍NULL之外呼叫它們時傳回 CATCH 。 您可以從區塊範圍內 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語句結束會話時。
當發生於與建構相同的執行CATCH層級時,區塊不會處理TRY...CATCH下列類型的錯誤:
造成無法執行批次的編譯錯誤,如語法錯誤。
在陳述式層級重新編譯期間發生的錯誤,例如在編譯之後,因延遲的名稱解析所發生的物件名稱解析錯誤。
物件名稱解析錯誤
這些錯誤會傳回執行批次、預存程序或觸發程序的層級。
如果在編譯或語句層級重新編譯期間發生錯誤,且執行層級較低(例如,在區塊內sp_executesql執行TRY或使用者定義預存程式時),則錯誤會在低於建構的層級TRY...CATCH發生,且將由相關聯的CATCH區塊處理。
下列範例示範 語句所產生的SELECT物件名稱解析錯誤不會由 TRY...CATCH 建構攔截,但在預存程式內執行相同CATCH語句時,區塊會攔截SELECT。
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。
Examples
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
相關內容
- 投擲 (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)
- 開始。。。結束(Transact-SQL)
- XACT_STATE(Transact-SQL)
- SET XACT_ABORT (Transact-SQL)