Подтвердить что ты не робот

Есть ли эквивалент в T-SQL для С# "throw"? перебросить исключения?

Название действительно является вопросом для этого: есть ли эквивалент в T-SQL для С# "throw"; перебросить исключения?

В С# можно сделать следующее:

try
{
    DoSomethingThatMightThrowAnException();
}
catch (Exception ex)
{
    // Do something with the exception
    throw; // Re-throw it as-is.
}

Есть ли что-то в функции T-SQL BEGIN CATCH, которая делает то же самое?

4b9b3361

Ответ 1

Вы можете использовать RAISERROR. Из документации MSDN в 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;

EDIT:

На самом деле это не то же самое, что С# throw или throw ex. Как указывает @henrikstaunpoulsen, вы не получаете исходный номер ошибки в новой ошибке (RAISERROR ограничен, в каких числах он может использовать). Вам нужно будет использовать какое-то соглашение и проанализировать информацию (если она доступна) из сообщения.

В MSDN есть статья Использование TRY... CATCH в 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.

Ответ 2

В SQL 2012 они добавили новое ключевое слово 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

Ответ 3

Вот что я использовал для отмены исключения после отката транзакции. Это также дает информацию о номере номера ошибки.

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

Ответ 4

Чтобы предотвратить повторение информации о процедуре/номера ошибок/строк в нескольких сценариях 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, мы не многократно добавляем дополнительную информацию, поэтому во внешней области видим только ошибку, как первоначально воссозданную.

В приведенных выше примерах результат с двойной ловушкой будет таким же, как вывод с одиночной ловушкой. Я также включаю уровень гнезда в сообщении об ошибке, чтобы помочь с отладкой.

Ответ 6

Обычно я использую следующее:

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