SQL Server 2005 前,錯誤處理靠 @@ERROR 全域變數檢查每條語句後狀態,程式碼冗長、易漏檢、難維護。TRY...CATCH 區塊帶來類 C#/Java 的結構化異常處理,大幅提升可讀性與健壯性。
BEGIN TRY
-- 可能發生錯誤的 T-SQL 陳述式
INSERT INTO Accounts (UserName, Balance) VALUES ('user1', 1000);
UPDATE Accounts SET Balance = Balance - 500 WHERE UserName = 'user1';
-- 成功路徑
SELECT 0 AS ResultCode; -- 或 RETURN 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;
-- 回滾交易 (若在交易中)
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
SELECT -1 AS ResultCode; -- 或 RETURN -1
END CATCH;
| 函數 | 回傳值 |
|---|---|
| ERROR_NUMBER() | 錯誤號 (如 2627 唯一鍵衝突、547 FK 衝突) |
| ERROR_SEVERITY() | 嚴重性等級 (10 以下資訊性、11-16 使用者可修正、17-25 系統錯誤) |
| ERROR_STATE() | 錯誤狀態碼 (同一錯誤號不同發生點) |
| ERROR_PROCEDURE() | 發生錯誤的預存程序/觸發器名稱 (NULL 為動態批次) |
| ERROR_LINE() | 發生錯誤的行號 |
| ERROR_MESSAGE() | 完整錯誤訊息文字 (含參數替換) |
CREATE PROCEDURE dbo.TransferFunds
@FromAccount INT, @ToAccount INT, @Amount MONEY
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
UPDATE Accounts SET Balance -= @Amount WHERE AccountID = @FromAccount;
IF @@ROWCOUNT = 0 THROW 50001, '轉出帳戶不存在', 1;
UPDATE Accounts SET Balance += @Amount WHERE AccountID = @ToAccount;
IF @@ROWCOUNT = 0 THROW 50002, '轉入帳戶不存在', 1;
INSERT INTO TransferLog (FromAcc, ToAcc, Amount, TxnDate)
VALUES (@FromAccount, @ToAccount, @Amount, GETDATE());
COMMIT TRANSACTION;
SELECT 0 AS ResultCode, 'Success' AS Msg;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
-- 記錄錯誤至日誌表
INSERT INTO ErrorLog (ProcName, ErrorNum, ErrorMsg, ErrorTime, Params)
VALUES (ERROR_PROCEDURE(), ERROR_NUMBER(), ERROR_MESSAGE(), GETDATE(),
CONCAT('@From=',@FromAccount,',@To=',@ToAccount,',@Amt=',@Amount));
-- 回傳給呼叫端
SELECT -1 AS ResultCode, ERROR_MESSAGE() AS Msg;
END CATCH;
END;
| 特性 | RAISERROR | THROW |
|---|---|---|
| 語法 | RAISERROR(msg, severity, state, ...) | THROW error_number, message, state |
| 重新拋出 | 需保存錯誤資訊再 RAISERROR | THROW; 在 CATCH 中直接重拋原錯誤 |
| 嚴重性 | 可指定 0-25 | 固定 16 (使用者錯誤) |
| 語句結束 | 不終止批次 (需 RETURN) | 終止當前批次/預存程序 |
建議:SQL Server 2012+ 統一使用 THROW;2005/2008/R2 使用 RAISERROR + RETURN。
SET XACT_ABORT ON 可確保嚴重錯誤 (如死鎖 1205) 自動回滾交易並進入 CATCHTHROW 外拋IF @@ERROR <> 0 檢查點BEGIN TRY...END TRYBEGIN CATCH...END CATCHRAISERROR 為 THROW (版本允許時)SET XACT_ABORT ON 於預存程序開頭ErrorLog 表與記錄預存程序TRY...CATCH 是 SQL Server 2005 最重要的 T-SQL 增強之一。它讓資料庫程式碼具備**現代程式語言級的錯誤處理能力**:集中處理、資訊豐富、交易安全、易於除錯。請在所有新開發與重構專案中全面採用。