[MSSQL]使用Try/Catch機制處理例外Exception錯誤

 在我們使用SQL時,可能會需要執行許多新增、修改的動作,但是可能會因為某一行邏輯錯誤造成例外(Exception)的發生,

而在發生例外錯誤的時候,程式會繼續執行完還是就停止執行了呢?答案是會繼續執行

這個問題可能很多人知道,但是曾經詢問前輩得到的是不同答案,讓我很驚訝

在這裡做個實驗驗證

測試EXCEPTION

我們先建立測試TABLE

IF OBJECT_ID('tempdb.dbo.#TBL') IS NOT NULL DROP TABLE #TBL
CREATE TABLE #TBL(ITEM INT)

接下來故意在第二次INSERT之後產生除以零的錯誤

INSERT INTO #TBL(ITEM) VALUES(1)
INSERT INTO #TBL(ITEM) VALUES(2)
SELECT 2/0
INSERT INTO #TBL(ITEM) VALUES(3)
SELECT * FROM #TBL

結果為如下 

完整範例

IF OBJECT_ID('tempdb.dbo.#TBL') IS NOT NULL DROP TABLE #TBL
CREATE TABLE #TBL(ITEM INT)
INSERT INTO #TBL(ITEM) VALUES(1)
INSERT INTO #TBL(ITEM) VALUES(2)
SELECT 2/0
INSERT INTO #TBL(ITEM) VALUES(3)
SELECT * FROM #TBL

實務上常常先對Table DELETE再去INSERT,如果INSERT遇到Primary Key衝突不就重新執行沒錯就沒事了

因此我會在執行多行的執行緒習慣包一層Try/Catch,使用方法和C#/C++幾乎相同,範例如下

Try/Catch範例
BEGIN TRY

--在這裡放你要執行的SQL語法

END TRY
BEGIN CATCH
--DB查詢用
	SELECT ERROR_NUMBER() AS ErrorNumber,
		   ERROR_MESSAGE() AS ErrorMessage,
		   ERROR_LINE() AS ErrorLine,
		   ERROR_PROCEDURE() AS ErrorProcedure,
		   ERROR_SEVERITY() AS ErrorSeverity,
		   ERROR_STATE() AS ErrorState

--系統拋回訊息用
	DECLARE @ErrorMessage As VARCHAR(1000) = CHAR(10)+'錯誤代碼:' +CAST(ERROR_NUMBER() AS VARCHAR)
											+CHAR(10)+'錯誤訊息:'+	ERROR_MESSAGE()
											+CHAR(10)+'錯誤行號:'+	CAST(ERROR_LINE() AS VARCHAR)
											+CHAR(10)+'錯誤程序名稱:'+	ISNULL(ERROR_PROCEDURE(),'')

	DECLARE @ErrorSeverity As Numeric = ERROR_SEVERITY()
	DECLARE @ErrorState As Numeric = ERROR_STATE()
	RAISERROR( @ErrorMessage, @ErrorSeverity, @ErrorState);--回傳錯誤資訊
END CATCH

在CATCH的地方,因為發生Exception會跳至BEGIN CATCH執行,當系統呼叫時會被系統認定為沒錯誤

因此使用RASERROR來故意錯誤訊息觸發

在這裡我們套用剛剛範例使用Try/Catch機制

IF OBJECT_ID('tempdb.dbo.#TBL') IS NOT NULL DROP TABLE #TBL
CREATE TABLE #TBL(ITEM INT)

BEGIN TRY

INSERT INTO #TBL(ITEM) VALUES(1)
INSERT INTO #TBL(ITEM) VALUES(2)
SELECT 2/0
INSERT INTO #TBL(ITEM) VALUES(3)
SELECT * FROM #TBL

END TRY
BEGIN CATCH
--DB查詢用
	SELECT ERROR_NUMBER() AS ErrorNumber,
		   ERROR_MESSAGE() AS ErrorMessage,
		   ERROR_LINE() AS ErrorLine,
		   ERROR_PROCEDURE() AS ErrorProcedure,
		   ERROR_SEVERITY() AS ErrorSeverity,
		   ERROR_STATE() AS ErrorState

--系統拋回訊息用
	DECLARE @ErrorMessage As VARCHAR(1000) = CHAR(10)+'錯誤代碼:' +CAST(ERROR_NUMBER() AS VARCHAR)
											+CHAR(10)+'錯誤訊息:'+	ERROR_MESSAGE()
											+CHAR(10)+'錯誤行號:'+	CAST(ERROR_LINE() AS VARCHAR)
											+CHAR(10)+'錯誤程序名稱:'+	ISNULL(ERROR_PROCEDURE(),'')
	DECLARE @ErrorSeverity As Numeric = ERROR_SEVERITY()
	DECLARE @ErrorState As Numeric = ERROR_STATE()
	RAISERROR( @ErrorMessage, @ErrorSeverity, @ErrorState);--回傳錯誤資訊
END CATCH

即可產生以下的錯誤訊息傳至系統的Exception消息

而我們最關心的資料表到底進去了多少資料呢?

實驗成功

建議此方法可以使用在Stored Procedures內,連錯誤的程序名稱也能監控到

如有觀念錯誤,請不吝指教