1. ryo_naka

    Posted

    ryo_naka
Changes in title
+SQLServerでTRY-CATCHしちゃうと呼び出し側でエラー判別したい
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,179 @@
+
+
+
+こんな感じの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
+https://docs.microsoft.com/ja-jp/sql/t-sql/language-elements/return-transact-sql?view=sql-server-2016
+
+>クエリまたはプロシージャを無条件で終了します。 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](https://qiita-image-store.s3.amazonaws.com/0/106639/a0ffd0c3-c112-caa2-10f0-05d6fa1ede17.png)
+
+**「このコンテキストでは、戻り値を返すRETURNステートメントは使用できません」**
+
+調べてみるとこういう使いかただとRETRUNは使えないらしい。
+※正直この辺はちょっとよく理解できていない。
+
+
+## THROW
+https://docs.microsoft.com/ja-jp/sql/t-sql/language-elements/throw-transact-sql?view=sql-server-2016
+
+>例外を発生させ、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は全然やってこなかったので、本当にこの解決法でいいのかどうかすらよくわからない。
+こんな乱暴じゃない解決法があるのであれば知りたいところ。。。
+