web-dev-qa-db-ja.com

SQLサーバーで同じ例外を再スローする方法

私のtryブロックで発生したSQLサーバーで同じ例外を再スローしたいです。私は同じメッセージを投げることができますが、同じエラーを投げたいです。

_BEGIN TRANSACTION
    BEGIN TRY
            INSERT INTO Tags.tblDomain 
            (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
            COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
            declare @severity int; 
            declare @state int;

            select @severity=error_severity(), @state=error_state();

            RAISERROR(@@Error,@ErrorSeverity,@state);
            ROLLBACK TRANSACTION
    END CATCH
_

RAISERROR(@@Error, @ErrorSeverity, @state);

この行にはエラーが表示されますが、そのような機能が必要です。これにより、エラー番号50000のエラーが発生しますが、_@@error_を渡そうとしているerron番号がスローされるようにします。

フロントエンドでこのエラーをキャプチャしません

つまり.

_catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
_

この機能が欲しい。 raiseerrorを使用して達成することはできません。バックエンドでカスタムエラーメッセージを表示したくありません。

RAISEERRORは、キャッチでスローされるErrorNoを渡すと、以下のエラーを返す必要があります

_Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
_

行14一意キー制約 'UK_DomainCode'の違反。オブジェクト 'Tags.tblDomain'に重複キーを挿入できません。ステートメントは終了されました。

編集:

ストアドプロシージャに実行する必要がある複数のクエリが含まれていることを考慮して、フロントエンドで例外を処理する場合、try catchブロックを使用しない場合の欠点は何ですか

77
Shantanu Gupta

エラーが発生した場合に一連のステートメントをロールバックし、エラーメッセージを報告する完全に機能するクリーンなコードサンプルを次に示します。

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
104
Ben Gripka

SQL 2012では、throwステートメントが導入されています。

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

パラメーターなしでTHROWステートメントを指定する場合、CATCHブロック内に表示する必要があります。これにより、キャッチされた例外が発生します。

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
119
Michael

CATCHブロック内で再スローします(SQL2012以前のコード。SQL2012以降ではTHROWステートメントを使用します)。

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
5
nzeemin

あなたの選択は次のとおりだと思います:

  • エラーをキャッチしない(バブルアップさせます)
  • カスタムのものを上げる

ある時点で、SQLはおそらくリレイズコマンド、または特定のエラーのみをキャッチする機能を導入します。しかし今のところ、回避策を使用してください。ごめんなさい。

4
Rob Farley

できない:50000未満のエラーをスローできるのはエンジンだけです。できることは、looksのような例外をスローすることだけです...

こちらの回答をご覧ください

ここの質問者は、クライアント側のトランザクションを使用して、彼が望んでいたことを実行しましたが、これはちょっとばかげていると思います...

1
gbn

まだ2012年に移行していない場合、元のエラーコードのバブリングアップを実装する1つの方法は、catchブロックから(再)スローしている例外のテキストメッセージ部分を使用することです。キャッチャーブロックで解析する呼び出し元コードのXMLテキストなど、何らかの構造を含めることができることに注意してください。

0
Yuri Makassiouk

エラーが発生した後にストアドプロシージャの実行を停止し、呼び出し元のプログラムにエラーをバブルバックする方法は、このコードでエラーをスローする可能性のある各ステートメントに従うことです。

If @@ERROR > 0
Return

ストアドプロシージャの実行がエラーの後も継続できることを知って驚いた-これを認識しないと、バグを追跡するのが困難になる可能性がある。

このタイプのエラー処理は(.Netより前の)Visual Basic 6に匹敵します。SQLServer 2012のThrowコマンドを楽しみにしています。

0
Chuck Bevitt

OK、これは回避策です... :-)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

Catchブロックに注意すると、エラーが発生するのではなく、実際のエラー番号が返されます(トランザクションもロールバックされます)。 .NETコードで、例外をキャッチする代わりに、ExecuteScalar()を使用すると、実際のエラー番号を取得し、適切な番号を表示します。

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

お役に立てれば、

編集:-注:影響を受けるレコードの数を取得してExecuteNonQueryを使用しようとすると、上記の解決策が機能しない場合があります。 。

0
Ashish Gupta

トランザクション内でSQLステートメントを実行し、コードにエラーをフィードする場合、これらのシナリオのラッパーストアドプロシージャを作成することもできます。

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
0
Sergey