2009-11-04 44 views

回答

33

您可以使用RAISERROR。從MSDN documentation上RAISERROR:

BEGIN TRY 
    -- RAISERROR with severity 11-19 will cause execution to 
    -- jump to the CATCH block 
    RAISERROR ('Error raised in TRY block.', -- Message text. 
       16, -- Severity. 
       1 -- State. 
       ); 
END TRY 
BEGIN CATCH 
    DECLARE @ErrorMessage NVARCHAR(4000); 
    DECLARE @ErrorSeverity INT; 
    DECLARE @ErrorState INT; 

    SELECT @ErrorMessage = ERROR_MESSAGE(), 
      @ErrorSeverity = ERROR_SEVERITY(), 
      @ErrorState = ERROR_STATE(); 

    -- Use RAISERROR inside the CATCH block to return 
    -- error information about the original error that 
    -- caused execution to jump to the CATCH block. 
    RAISERROR (@ErrorMessage, -- Message text. 
       @ErrorSeverity, -- Severity. 
       @ErrorState -- State. 
       ); 
END CATCH; 

編輯:

這不是真正的同樣的事情,C#的throwthrow ex。正如@henrikstaunpoulsen指出,你不會在新錯誤中得到原始錯誤號(RAISERROR被限制在可以使用的數字中)。您將不得不使用某種約定,並從消息中解析信息(如果可用)。

MSDN有一篇文章Using TRY...CATCH in Transact-SQL,我使用一些代碼來創建以下測試:

use test; 
GO 

IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL 
    DROP PROCEDURE usp_RethrowError; 
GO 

CREATE PROCEDURE usp_RethrowError AS 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 

    DECLARE 
     @ErrorMessage NVARCHAR(4000), 
     @ErrorNumber  INT, 
     @ErrorSeverity INT, 
     @ErrorState  INT, 
     @ErrorLine  INT, 
     @ErrorProcedure NVARCHAR(200); 

    SELECT 
     @ErrorNumber = ERROR_NUMBER(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(), 
     @ErrorLine = ERROR_LINE(), 
     @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-'); 

    SELECT @ErrorMessage = 
     N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
      'Message: '+ ERROR_MESSAGE(); 

    RAISERROR 
     (
     @ErrorMessage, 
     @ErrorSeverity, 
     @ErrorState,    
     @ErrorNumber, -- parameter: original error number. 
     @ErrorSeverity, -- parameter: original error severity. 
     @ErrorState,  -- parameter: original error state. 
     @ErrorProcedure, -- parameter: original error procedure name. 
     @ErrorLine  -- parameter: original error line number. 
     ); 
GO 

PRINT 'No Catch' 
DROP TABLE XXXX 

PRINT 'Single Catch' 
BEGIN TRY 
    DROP TABLE XXXX 
END TRY 
BEGIN CATCH 
    EXEC usp_RethrowError; 
END CATCH; 

PRINT 'Double Catch' 
BEGIN TRY 
    BEGIN TRY 
     DROP TABLE XXXX 
    END TRY 
    BEGIN CATCH 
     EXEC usp_RethrowError; 
    END CATCH; 
END TRY 
BEGIN CATCH 
    EXEC usp_RethrowError; 
END CATCH; 

將會產生以下的輸出:

No Catch 
Msg 3701, Level 11, State 5, Line 3 
Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
Single Catch 
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25 
Error 3701, Level 11, State 5, Procedure -, Line 7, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
Double Catch 
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25 
Error 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25, Message: Error 3701, Level 11, State 5, Procedure -, Line 16, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
+1

是不是有這個問題,在錯誤號爲與原始異常不同? – 2009-11-06 12:26:38

+0

@henrikstaunpoulsen是的,你是對的。我不認爲這在T-SQL或其他任何方式中都是可行的。我更新了這篇文章,提供了更多關於這一點的信息 – ongle 2009-11-06 16:43:34

+0

在SQL 2012中有新的關鍵字THROW – sergiom 2013-02-27 10:45:51

0

我一般使用以下方法:

DECLARE @Outcome as bit 
DECLARE @Error as int 

BEGIN TRANSACTION 

-- *** YOUR TSQL TRY CODE HERE **** 


-- Capture the TSQL outcome. 
SET @Error = @@ERROR 

-- Set the Outcome to be returned to the .NET code to successful 
SET @Outcome = 1 


IF @Error <> 0 
    BEGIN 
     -- An Error was generate so we invoke ROLLBACK 
     ROLLBACK 
     -- We set the Outcome to be returned to .Net to unsuccessful 
     SET @Outcome = 0 
    end 

ELSE 
    BEGIN 
     -- The transaction was successful, invoke COMMIT 
     COMMIT 
    END 



-- Returning a boolean value to the .NET code 
Select @Outcome as Outcome 
+0

如果你只檢查@@ ERROR一次,你不會只檢測到你的SQL代碼的最後一個語句中的錯誤嗎?例如。 'SELECT 1/0;選擇1; SELECT @@ ERROR'給出的錯誤爲0.使用@@ ERROR似乎比使用TRY CATCH塊更差。 – Jim 2016-05-31 10:55:50

2

這是我已經習慣了重新拋出回滾事務後異常。這也給出了錯誤的行號信息。

BEGIN TRY 
    BEGIN TRANSACTION -- Start the transaction 

    -- Do your work here 

    -- Commit the transaction 
    COMMIT TRANSACTION 

END TRY 

BEGIN CATCH 
    -- There was an error, rollback the transaction 
    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION 

    -- Raise an error with the details of the exception 
    DECLARE @ErrorMessage nvarchar(2048) 
    DECLARE @ErrorProcedure nvarchar(128) 
    DECLARE @ErrorState int 
    DECLARE @ErrorLine int 
    DECLARE @ErrorSeverity int 

    SET @ErrorProcedure = ERROR_PROCEDURE() 
    SET @ErrorLine = ERROR_LINE() 
    SET @ErrorSeverity = ERROR_SEVERITY() 
    SET @ErrorState = ERROR_STATE() 
    SET @ErrorMessage = '' 

    IF @ErrorProcedure IS NOT NULL 
     SET @ErrorMessage = @ErrorMessage + @ErrorProcedure + ' '; 

    IF @ErrorLine IS NOT NULL 
     SET @ErrorMessage = @ErrorMessage + '[Line ' + CAST(@ErrorLine as nvarchar) + '] '; 

    SET @ErrorMessage = @ErrorMessage + ERROR_MESSAGE() 

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState) 
END CATCH 
2

爲了防止程序的信息/錯誤/行號的重複在多個catch情況下,我使用了類似的方法,使用稍加修改如下:

IF @Error_Procedure <> OBJECT_NAME(@@PROCID)  
    BEGIN 
     RAISERROR('[Procedure: %s]: Nest Level: %d; Line: %d; Error Number: %d; Message: %s',@Error_Severity,@Error_State,@Error_Procedure, @NestLevel, @Error_Line, @Error_Number, @Error_Message) 
    END 
ELSE 
    BEGIN 
     RAISERROR(@Error_Message,@Error_Severity,@Error_State) 
    END 

因此,如果我們有已經發現並重新提出了這個SP的錯誤,我們不會重複添加附加信息,所以在外部範圍,我們只能看到最初重新提出的錯誤。

在上面的示例中,雙捕獲輸出將與單捕獲輸出相同。我還在錯誤消息中包含了嵌套級別以幫助進行調試。

14

2012年SQL他們增加了新的throw關鍵字,也可以用來重新拋出異常

USE tempdb; 
GO 
CREATE TABLE dbo.TestRethrow 
( ID INT PRIMARY KEY 
); 
BEGIN TRY 
    INSERT dbo.TestRethrow(ID) VALUES(1); 
-- Force error 2627, Violation of PRIMARY KEY constraint to be raised. 
    INSERT dbo.TestRethrow(ID) VALUES(1); 
END TRY 
BEGIN CATCH 

    PRINT 'In catch block.'; 
    THROW; 
END CATCH; 

http://msdn.microsoft.com/en-us/library/ee677615.aspx

相關問題