真沒想到這麼快就又見面了!
趁著記憶猶新,趕緊來記錄一下小弟我所發現關於SQL Server動態T-SQL的Error Handling現象。
一般來說,T-SQL錯誤處理的方法有兩種。
1. 使用@@ERROR系統全域變數:
此全域變數會記錄上一個T-SQL語句查詢的結果,也就是說隨著執行過程,@@ERROR會一直改變。
也就是說,如果是一串的SQL指令,每一句都需要做Error Handle的話,可能使用下一種方法會更為合適。
2. 使用TRY...CATCH:
就跟一般高階語言(C#、JAVA等)的用法類似,就不再贅述了...
進入重頭戲啦!
還記得先前做動態T-SQL建立資料庫嗎?回憶傳送門
先來看一段T-SQL的語法。
declare @DBName nvarchar(50), @Sqlcmd nvarchar(max) set @DBName = N'HowardDB' set @Sqlcmd = 'USE [master] CREATE DATABASE ['+@DBName+'] ON PRIMARY ( NAME = N'''+@DBName+''', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'.mdf'' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'''+@DBName+'_log'', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'_log.ldf'' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)' -------------錯誤處理1----------- BEGIN TRY execute sp_executesql @Sqlcmd END TRY BEGIN CATCH print ERROR_MESSAGE() END CATCH -----------錯誤處理2----------- execute sp_executesql @Sqlcmd if(@@ERROR<>0) begin print 'Dymanic T-SQL Error' end
這是一段動態組成建立資料庫的語法,底下有兩種執行動態T-SQL後錯誤處理的方法
可以看到兩種方法都可以成功取的錯誤並進行錯誤的處理。
那我們把這段動態語法做點手腳來執行看看吧~
declare @DBName nvarchar(50), @Sqlcmd nvarchar(max) set @DBName = N'HowardDB' set @Sqlcmd = 'USE [master] CREATE DATABASE ['+@DBName+'] ON PRIMARY ( NAME = N'''+@DBName+''', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'.mdf'' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'''+@DBName+'_log'', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'_log.ldf'' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) select @@version' -------------錯誤處理1----------- BEGIN TRY execute sp_executesql @Sqlcmd END TRY BEGIN CATCH print ERROR_MESSAGE() END CATCH -----------錯誤處理2----------- execute sp_executesql @Sqlcmd if(@@ERROR<>0) begin print 'Dymanic T-SQL Error' end
奇蹟的事情發生了!@@ERROR沒有擷取到錯誤!
原來是因為他機制的關係,他只會記錄上一個T-SQL語句查詢的結果(select @@version)。
再來觀察一個結果...
但仔細看可以發現,查詢結果只出現了一個查詢。
因為Try Catch則在T-SQL發生任何錯誤就不再執行接下來的查詢,直接進入到Catch的階段。
這次我們在建立資料庫的語法上亂搞試看看...
declare @DBName nvarchar(50), @Sqlcmd nvarchar(max) set @DBName = N'HowardDB' set @Sqlcmd = 'USE [master] CREAT DATABASE ['+@DBName+'] ON PRIMARY ( NAME = N'''+@DBName+''', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'.mdf'' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'''+@DBName+'_log'', FILENAME = N''C:\Program Files\Microsoft SQL Server \MSSQL10.SQLEXPRESS\MSSQL\DATA\'+@DBName+'_log.ldf'' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) select @@version' -------------錯誤處理1----------- BEGIN TRY execute sp_executesql @Sqlcmd END TRY BEGIN CATCH print ERROR_MESSAGE() END CATCH -----------錯誤處理2----------- execute sp_executesql @Sqlcmd if(@@ERROR<>0) begin print 'Dymanic T-SQL Error' end
很好,TRY-CATCH一直表現的非常良好,而@@ERROR這次也有擷取到錯誤了!
查了一些資料,原來這樣的語法錯誤屬於fatal error,錯誤等級很高,動態T-SQL直接終止,select @@version根本沒有執行。
總結一下:
1. @@ERROR只存放上一句T-SQL查詢的結果。若是動態T-SQL查詢也是同樣情形,除非錯誤等級很高。
2. Try Catch則在T-SQL發生任何錯誤(都擷取的到)就直接終止查詢(機制就跟C#、JAVA一樣)
3. 感覺各有優缺點,就看應用選擇吧~
p.s.今天跟同事討論,討論到關於寫程式遇到問題時的思維,發現難免都會依照過去經驗而有所謂「腦補」的現象。
例如這篇文章的內容,@@ERROR特性從認為在預存程序中不穩定、以為只有CREATE/ALTER相關語法才會無法擷取到最後筆記下來的最終內容。
有了這次的經驗,時間充裕的話,還是多去嘗試、了解,以免誤人子弟...
參考資料:
TechNet - 在 Transact-SQL 中使用 TRY...CATCH
https://technet.microsoft.com/zh-tw/library/ms179296(v=sql.105).aspx
@@ERROR not return anything for some error
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=88760
Can not get @@ERROR after EXEC() with Error
http://stackoverflow.com/questions/10148061/can-not-get-error-after-exec-with-error
沒有留言:
張貼留言