2013-02-26 110 views
2

我有一個存儲過程,似乎沒有正確記錄其錯誤。嘗試和抓住TSQL - 趕不捕獲

代碼錯誤,但catch塊似乎不會生效。

try塊相當長 - 但錯誤部分很簡單,並在最後直接出現,所以我已經精確定義了這一點。

BEGIN TRY 
insert into tbl_X 
select * from #temp_tbl_Y 

RETURN 1 
END TRY 

BEGIN CATCH 
    Insert Into ExtractsErrorLog 
    SELECT 
    getdate() as ErrorDate 
    ,object_name(@@procid) as ProcedureName 
    ,ERROR_NUMBER() as ErrorNumber 
    ,ERROR_LINE() as ErrorLine 
    ,ERROR_MESSAGE() as ErrorMessage 
    ; 
DECLARE @errormessage as varchar(max); 
DECLARE @errorseverity as int; 
DECLARE @errorstate as int; 

set @errormessage = ERROR_MESSAGE(); 
set @errorseverity = ERROR_SEVERITY(); 
set @errorstate = ERROR_STATE(); 

RAISERROR (@errormessage, 
      @errorseverity, 
      @errorstate 
       ); 


END CATCH; 

的PROC失敗上的錯誤是我們的老朋友 「列名或所提供值不匹配表定義的數量。」 我修復了這個錯誤 - 這是一個愚蠢的懶惰錯誤 - 但我很困惑爲什麼我的錯誤日誌記錄過程似乎沒有工作 - 沒有行被插入到我的ExtractsErrorLog表中。

+2

這是一個編譯時錯誤,請參閱本:http://stackoverflow.com/questions/7286667/sql-try-catch-statement-not-handling-error- sql-server-2008 – 2013-02-26 15:24:15

+0

你可以發佈'ExtractsErrorLog'的表定義嗎? – Lamak 2013-02-26 16:07:34

+0

感謝Ivan - 這很有道理 - 並且該線程也提供了一種解決方法。對不起,錯過了它並轉貼。我讀過這個catch沒有捕獲編譯 - 但我沒有扭轉,這將是一個編譯錯誤。 有誰知道是否有一個在線指南,瞭解編譯/重新編譯時會出現什麼錯誤。我可以明白爲什麼這會是一個現在,我想也缺少表等?但我想確定一下,我沒有太多的細節。 – DanBennett 2013-02-27 11:20:35

回答

6

TSQL的TRY...CATCH不會捕獲該錯誤。此錯誤屬於「編譯/重新編譯」類型的錯誤,它不會由「在相同執行級別內」的CATCH塊來處理。

MSDN

  • 編譯:

    以下類型的錯誤時 它們出現在相同的水平執行的作爲TRY ... CATCH構造不是由CATCH塊處理錯誤(例如語法錯誤)會阻止 批處理運行。編譯後發生

  • 錯誤中語句級重新編譯發生,例如 作爲對象名解析錯誤,因爲延遲名稱解析

的 ...

你可以使用TRY ... CATCH來處理編譯期間發生的錯誤 或通過執行錯誤生成進行語句級重新編譯代碼在TRY塊內的單獨批處理中。例如,您通過將代碼放入存儲過程中或通過使用sp_executesql執行動態Transact-SQL語句來執行 。這允許 TRY ... CATCH捕獲錯誤發生時的執行級別高於 。例如,以下代碼顯示存儲的 過程,該過程會生成對象名稱解析錯誤。包含TRY ... CATCH結構的批次 在存儲過程的更高級別 處執行;並且發生在較低的 級別的錯誤被捕獲。

我遇到了類似的問題與腳本創建TRY...CATCH內部事務,如果失敗,將ROLLBACK交易。交易內部的一個聲明拋出了相同的錯誤,並導致交易永不結束,因爲從未輸入過CATCH

正如在MSDN文章中提到的,一種替代方法是從INSERT語句中創建一個存儲過程,然後在try/catch中調用該過程。如果存儲過程錯誤,您將在嘗試創建時收到編譯錯誤。如果表定義後來更改爲使存儲過程無效,那麼TRY...CATCH將爲您捕獲異常。

如果您希望它全部生活在一個腳本中,您可以將其設置爲temporary stored procedure,但在創建sprocs時需要處理編譯錯誤。這不是很漂亮,但它會工作:

-- Creating error sproc to re-use code 
CREATE PROCEDURE #HandleError AS 
    Insert Into ExtractsErrorLog 
    SELECT GETDATE() as ErrorDate 
      ,object_name(@@procid) as ProcedureName 
      ,ERROR_NUMBER() as ErrorNumber 
      ,ERROR_LINE() as ErrorLine 
      ,ERROR_MESSAGE() as ErrorMessage; 

    DECLARE @errormessage as varchar(max); 
    DECLARE @errorseverity as int; 
    DECLARE @errorstate as int; 

    set @errormessage = ERROR_MESSAGE(); 
    set @errorseverity = ERROR_SEVERITY(); 
    set @errorstate = ERROR_STATE(); 

    RAISERROR (@errormessage, 
       @errorseverity, 
       @errorstate); 
GO 

-- Create a stored procedure of our INSERT and catch any compilation errors 
CREATE PROCEDURE #TEST AS 
    insert into tbl_X 
    select * from #temp_tbl_Y 
GO 
IF (@@ERROR <> 0) BEGIN 
    exeC#HandleError 
    -- If there was an error creating the sprocs, don't continue to the next batch 
    RETURN 
END 

-- If compilation succeeded, then run the sproc 
BEGIN TRY 
    exeC#TEST 
    RETURN 
END TRY 
BEGIN CATCH 
    exeC#HandleError 
END CATCH; 
-1

這是您的RETURN:「無條件退出查詢或過程.RETURN是即時且完整的,可用於任何點退出過程,批處理或語句塊。

+0

'RETURN'沒有被達到,如''所提供的值的列名或數量與表定義不匹配。「'錯誤... – 2013-02-26 19:10:54

+0

謝謝拉塞爾 - 儘管我同意邁克爾,我很公平某些回報未達到。 感謝所有人對此的幫助 - 我想伊萬有上面的答案。 – DanBennett 2013-02-27 11:24:32