BEGIN TRY
-- 業務邏輯:可能拋出錯誤的 DML/DDL
INSERT INTO accounts (id, balance) VALUES (1, -100); -- 假設有 CHECK 約束 balance >= 0
END TRY
BEGIN CATCH
-- 1. 取得錯誤詳情
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
-- 2. 記錄日誌(自定義表)
INSERT INTO error_log (err_msg, severity, state, proc_name, log_time)
VALUES (@ErrorMessage, @ErrorSeverity, @ErrorState, 'usp_Transfer', SYSDATETIME());
-- 3. 重新拋出(保持原始錯誤資訊給上層)
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH;
| 函式 | 回傳 | 說明 |
|---|---|---|
ERROR_NUMBER() | int | 錯誤號(如 547 為 FK 衝突) |
ERROR_SEVERITY() | int | 嚴重級 1–25(≥20 為系統致命) |
ERROR_STATE() | int | 錯誤狀態碼,同錯誤號不同位置可能不同 |
ERROR_PROCEDURE() | sysname | 發生錯誤的預存程序/觸發器名 |
ERROR_LINE() | int | 批次/程序內行號 |
ERROR_MESSAGE() | nvarchar(4000) | 完整錯誤文本(含參數值) |
RAISERROR (msg_str, severity, state [, argument ...] )
-- 或格式化
RAISERROR (N'自訂訊息: %s, 代碼: %d', 16, 1, @param1, @param2);
severity 0–18 使用者可拋,19–25 需 sysadmin 權限且需 WITH LOG。state 0–255,建議保持原 ERROR_STATE(),便於追蹤來源。BEGIN CATCH
THROW; -- 直接重拋原始錯誤,保留堆疊、行號、狀態,語法更簡潔
END CATCH;
THROW 不需變數,自動保留完整錯誤上下文。THROW 50001, '自訂業務錯誤', 1;BEGIN TRY
BEGIN TRANSACTION;
-- 多條 DML
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW;
END CATCH;
TRY...CATCH + ERROR_*() 函式是 SQL Server 結構化錯誤處理基石。生產環境建議:統一錯誤日誌表、CATCH 區塊記錄完整上下文、用 THROW 重拋,確保監控系統能精準告警、開發能快速定位。