LoginSignup
6
5

More than 5 years have passed since last update.

SQLServerでTRY-CATCHしちゃうと呼び出し側でエラー判別しにくい

Last updated at Posted at 2019-03-02

こんな感じのSQLをファイルにし、BATファイルにてsqlcmdを使って呼び出した。

[Sample.sql]
    BEGIN TRY
        -- トランザクション開始
        BEGIN TRANSACTION;

        -- クリア
        DELETE FROM TAEGET_TABLE;

        INSERT INTO 
            TAEGET_TABLE
            SELECT
                FT.CD,
                FT.FIELD1,
                FT.FIELD2
            FROM
                FROM_TABLE FT

        -- コミット
        COMMIT TRANSACTION;
    END TRY

    BEGIN CATCH 
        -- エラー情報
        SELECT
            ' [ERR-LINE] ' + CONVERT(VARCHAR, IsNull(ERROR_LINE(),''))
            + ' [ERR-MESSAGE] ' + IsNull(ERROR_MESSAGE(),'')
            + ' [ERR-NUMBER] ' +  CONVERT(VARCHAR, IsNull(ERROR_NUMBER(),''))
            + ' [ERR-PROCEDURE] ' +  CONVERT(VARCHAR, IsNull(ERROR_PROCEDURE(),''))
            + ' [ERR-SEVERITY] ' +  CONVERT(VARCHAR, IsNull(ERROR_SEVERITY(),''))
            + ' [ERR-STATE] ' +  CONVERT(VARCHAR, IsNull(ERROR_STATE(),''));

        -- ロールバック
        ROLLBACK TRANSACTION;

    END CATCH;
<Sample.bat>
sqlcmd %DB_AUTH_SQLCMD% -S %DB_SERVERNAME% -d %DB_DBNAME% -b -i Sample.sql
if %ERRORLEVEL% NEQ 0 goto ERROR

※環境変数はあらかじめ設定されているものとします

しかしこれだと%ERRORLEVEL%でエラーを判別しようと思っても上手くいかない。
まあTRY-CATCHで握りつぶしてしまっているのだからわからなくもない。

しかしSQL的にはエラーなのでエラールート処理へ進んでいきたい。

ERROR_NUMBER

調べてみるとこういう関数がある
https://docs.microsoft.com/ja-jp/sql/t-sql/functions/error-number-transact-sql?view=sql-server-2016

この関数は、TRY...CATCH 構造の CATCH ブロックが実行される原因となったエラーのエラー番号を返します。

すごいやないかと思ったが、別にこの関数はエラー番号を返してくれるわけでもなく。
そもそもCATCHの中で使ってたし。

RETURN

クエリまたはプロシージャを無条件で終了します。 RETURN は即時に実行され、完了します。また、プロシージャ、バッチ、またはステートメント ブロックを終了する任意の位置で使用できます。 RETURN の後に続くステートメントは実行されません。

難しく考えることなくCATCHの中でRETRUNしてコード値を適当に返せばいいやん。

こうか?

    BEGIN TRY
        -- トランザクション開始
        BEGIN TRANSACTION;

        -- クリア
        DELETE FROM TAEGET_TABLE;

        INSERT INTO 
            TAEGET_TABLE
            SELECT
                FT.CD,
                FT.FIELD1,
                FT.FIELD2
            FROM
                FROM_TABLE FT

        -- コミット
        COMMIT TRANSACTION;

        RETURN 0
    END TRY

    BEGIN CATCH 
        -- エラー情報
        SELECT
            ' [ERR-LINE] ' + CONVERT(VARCHAR, IsNull(ERROR_LINE(),''))
            + ' [ERR-MESSAGE] ' + IsNull(ERROR_MESSAGE(),'')
            + ' [ERR-NUMBER] ' +  CONVERT(VARCHAR, IsNull(ERROR_NUMBER(),''))
            + ' [ERR-PROCEDURE] ' +  CONVERT(VARCHAR, IsNull(ERROR_PROCEDURE(),''))
            + ' [ERR-SEVERITY] ' +  CONVERT(VARCHAR, IsNull(ERROR_SEVERITY(),''))
            + ' [ERR-STATE] ' +  CONVERT(VARCHAR, IsNull(ERROR_STATE(),''));

        -- ロールバック
        ROLLBACK TRANSACTION;
        RETURN -1

    END CATCH;

どうやらコトはそう簡単ではないらしい。

image.png

「このコンテキストでは、戻り値を返すRETURNステートメントは使用できません」

調べてみるとこういう使いかただとRETRUNは使えないらしい。
※正直この辺はちょっとよく理解できていない。

THROW

例外を発生させ、TRY...CATCH 構造の CATCH ブロックに実行制御を移します。

例外を握りつぶしてしまっているのがダメならば、そのままTHROWでいいのでは?

こんな感じ。

    BEGIN TRY
        -- トランザクション開始
        BEGIN TRANSACTION;

        -- クリア
        DELETE FROM TAEGET_TABLE;

        INSERT INTO 
            TAEGET_TABLE
            SELECT
                FT.CD,
                FT.FIELD1,
                FT.FIELD2
            FROM
                FROM_TABLE FT

        -- コミット
        COMMIT TRANSACTION;
    END TRY

    BEGIN CATCH 
        -- エラー情報
        SELECT
            ' [ERR-LINE] ' + CONVERT(VARCHAR, IsNull(ERROR_LINE(),''))
            + ' [ERR-MESSAGE] ' + IsNull(ERROR_MESSAGE(),'')
            + ' [ERR-NUMBER] ' +  CONVERT(VARCHAR, IsNull(ERROR_NUMBER(),''))
            + ' [ERR-PROCEDURE] ' +  CONVERT(VARCHAR, IsNull(ERROR_PROCEDURE(),''))
            + ' [ERR-SEVERITY] ' +  CONVERT(VARCHAR, IsNull(ERROR_SEVERITY(),''))
            + ' [ERR-STATE] ' +  CONVERT(VARCHAR, IsNull(ERROR_STATE(),''));

        -- ロールバック
        ROLLBACK TRANSACTION;
        THROW;

    END CATCH;

とりあえずこれでやりたかったことは実現できそうな感じにはなった。

終わりに

SQLは全然やってこなかったので、本当にこの解決法でいいのかどうかすらよくわからない。
こんな乱暴じゃない解決法があるのであれば知りたいところ。。。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5