2015-09-19 121 views
2

所以我最近開始在大學的SQL Server中進行事務和錯誤處理,並且遇到了這個問題,我的老師一直無法解釋。當我嘗試並執行此塊:嘗試在SQL Server中捕獲?

Begin Transaction TRA 
    Begin Try 
    Alter Table history 
    Add Primary Key (employee_id,date_beg) 
    End Try 
    Begin catch 
    If @@trancount>0 
    Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje 
    End Catch 
Commit 

我收到以下錯誤信息:

消息8111,級別16,狀態1,2號線
無法定義的空列PRIMARY KEY約束在表'歷史'。

Msg 1750,Level 16,State 0,Line 2
無法創建約束。查看以前的錯誤。

所以它看起來代碼沒有捕獲錯誤,因爲它應該。

如果你能幫助我,我會非常感激!

+1

你看過Try ... Catch上的任何文檔嗎? [此MSDN頁面](https://msdn.microsoft.com/en-GB/library/ms175976.aspx)指出並非所有錯誤都被捕獲... – ChipsLetten

+1

@ChipLetten。 。 。這是一個16級錯誤,它是運行時,而不是編譯時。所以,它似乎應該被抓住。 –

回答

0

按照該BOL,嘗試捕捉時不工作:

期間語句級重新編譯不會 防止批次進行編譯時發生錯誤,但會盡快終止該批次爲 該語句的重新編譯失敗。例如,如果一個批次 有兩個語句,而第二個語句引用了一個不存在 的表,則延遲名稱解析會導致該批次成功編譯 ,並開始執行,而不會將缺失的表綁定到查詢計劃的 ,直到該語句爲重新編譯。批次停止 當它到達引用缺少的 表的語句並返回錯誤時運行。 TRY ... CATCH構造不會在 錯誤發生時的相同執行級別處理此類錯誤。

Methinx這是這裏的問題。

2

根據documentation on TRY...CATCH,我認爲你的CATCH塊應該已經發現了錯誤。

這些都是記錄在案的原因的錯誤不會在TRY...CATCH塊被抓,其中沒有一個似乎適用於您的情況:

TRY…CATCH結構不陷阱以下條件:

  • 嚴重性爲10或更低的警告或信息性消息。
  • 嚴重程度爲20或更高的錯誤會停止會話的SQL Server數據庫引擎任務處理。如果發生嚴重性爲20或更高的錯誤,並且數據庫連接沒有中斷,則TRY…CATCH將處理該錯誤。
  • 注意,例如客戶端中斷請求或客戶端連接斷開。
  • 當會話由系統管理員通過使用KILL語句結束時。

    • 編譯錯誤,如語法錯誤,即防止了一批:

    以下類型的錯誤,當他們出現在相同的水平執行的作爲TRY…CATCH構建體沒有被CATCH塊處理從跑步。

  • 語句級重新編譯期間發生的錯誤,例如由於延遲名稱解析而在編譯後發生的對象名稱解析錯誤。

考慮尤其是在過去2個原因,這不是一個編譯錯誤,也不是延遲名稱解析錯誤,因爲你的表名解析就好了。這確實是一個運行時錯誤,應該被捕獲。

然而,即使它不應該是適用在這裏,你會發現以下信息提供您的情況下,有效的解決方案:

如果在編譯或語句級重新編譯發生錯誤在TRY塊內的較低執行級別(例如,在執行sp_executesql或用戶定義的存儲過程時),錯誤發生在比TRY…CATCH構造更低的級別,並且將由關聯的CATCH塊處理。

應用以上信息,你會發現,你可以通過改變你的腳本以下任一2個選項捕獲錯誤:

選項1:sp_executesql的

Begin Transaction TRA 
    Begin Try 
    exec sp_executesql 'Alter Table history Add Primary Key (employee_id,date_beg)'; 
    End Try 
    Begin catch 
    If @@trancount>0 
    Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje 
    End Catch 
Commit 

選項2:在單獨的存儲過程中包裝alter語句

create procedure WrapAlterStatementInSP as 
Alter Table history Add Primary Key (employee_id,date_beg); 
go 

Begin Transaction TRA 
    Begin Try 
    exec WrapAlterStatementInSP; 
    End Try 
    Begin catch 
    If @@trancount>0 
    Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje 
    End Catch 
Commit 

希望這會有所幫助。但我確實認爲目前的行爲存在缺陷,或者文檔中缺少信息。

+0

它怎麼能不是一個延期名稱問題?該操作正在創建一個新的對象(主鍵約束),該過程在編譯時不存在。 https://technet.microsoft.com/en-us/library/ms190686(v=sql.105).aspx –

+0

@Rachel:如果'history'表不存在,則會發生延遲名稱解析錯誤。 OP的錯誤是*正在執行alter語句的結果,而不是語句級別的重新編譯/延遲名稱解析錯誤。 – sstan

+0

約束是一個對象,它在創建之前不存在。我有很多有趣的時間不得不迫使像這樣的批處理,只是爲了強迫他們,正如答案所暗示的。所以你的方法我覺得是100%有效的,只是你的想法,這是我覺得可疑的錯誤。你應該得到魔豆,因爲你提出了一個解決方案,我所做的只是描述了這個問題。相應提高。 –