TSQL のストアドでTRY CATCH の使い方を紹介してきた。

ではカスタムエラーをどう実現するかということになるがTSQLにRAISERROR()という関数が用意されている。
今回はこのRAISERROR()の使い方を簡単に紹介しよう。

◇基本的な構文

RAISERROR ( { msg_id | msg_str | @local_variable }
{ ,severity ,state }
[ ,argument [ ,...n ] ] )
[ WITH option [ ,...n ] ]

◇メッセージの作成

1. メッセージ文字の指定
まず、最初の引数 { msg_id | msg_str | @local_variable } に注目してみると3つの使い分けができるという意味である。これを簡単に書くと以下の通り

・msg_id ---- メッセージIDを指定する(あらかじめメッセージ登録が必要)
・msg_str ---- メッセージ文字を指定(メッセージ中に動的な変数も使える)
・@local_variable ---- msg_strを変数に格納して提供することができる

3つの使い分けと述べたが実際はあらかじめDBにメッセージを登録して使う方法とTSQL内で生成してメッセージを出力する場合の違いである。




msg_id を使うにはあらかじめ sp_addmessage を使って登録しますが、実際の開発現場ではほとんど使うことがないので今回は省く。

1.-1msg_str の使い方
msg_str はC 標準ライブラリに含まれる printf 関数に似た形式のユーザー定義メッセージである。エラー メッセージの長さは最大 2,047 文字まで。

文字をメッセージとして戻す単純な方法

RAISERROR ('TEST ERROR 発生', -- メッセージID.
10, -- 重大度,
1) -- State
GO

メッセージ内に数値変数を入れて生成する方法

メッセージ内に文字を入れて生成する場合と文字の位置、長さを指定する方法

置き換え文字の種類(Help から)


1.-2 @local_variableを使った方法
@local_variable を使うのはメッセージを動的に変更したい場合などに有効である。
上記で述べてきたmsg_str を変数に入れて使うことにより、適切な動的メッセージを作ることができる。

画像だと大きくなるので使ったTSQLを文字で紹介

DECLARE @RefString NVARCHAR(100);
SET @RefString = '関数処理AAA'

RAISERROR ('01 TEST ERROR %3.1s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

RAISERROR ('02 TEST X ERROR %3.2s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

RAISERROR ('03 TEST X ERROR %3.3s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

RAISERROR ('04 TEST X ERROR %10.9s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

RAISERROR ('05 TEST X ERROR %10.6s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

RAISERROR ('06 TEST X ERROR %6s発生', -- メッセージID.
10, -- 重大度,
1, -- State
 @RefString);      -- %s に入る文字

結果の表示


2. severity (重大度)とは
Helpから

0 から 18 までの重大度レベルはどのユーザーでも指定できます。19 から 25 までの重大度レベルは、固定サーバー ロール sysadmin のメンバ、または ALTER TRACE 権限のあるユーザーのみが指定できます。重大度レベル 19 から 25 までは、WITH LOG オプションを必要とします。

ユーザが設定する場合0-18までの値を自由に設定できますが、TRY CATCH を使ったERROR処理を実装する場合、重大度10以下ではCATCH ブロックに処理が渡されないので、基本的に11 - 18までとなる。

上記のテストでは重大度を10としてERRORとならず結果を表示するように指定していたが重大度を18とすると以下のようになる

DECLARE @RefString NVARCHAR(100);
SET @RefString = '関数処理AAA'

RAISERROR ('01 TEST ERROR %3.1s発生', -- メッセージID.
18, -- 重大度,
1, -- State
@RefString); -- %s に入る文字

上記の結果

3. state とは
Helpから

1 〜 127 の任意の整数です。state に負の値が設定されている場合は、既定値が 1 になります。0 または 127 より大きい値に設定されている場合は、エラーが発生します。
同じユーザー定義エラーが複数の場所で発生する場合、それぞれの場所に対して一意の状態番号を使用すると、コードのどのセクションでエラーが発生しているのかを探すのに役立ちます。

簡単にいえば処理番号をストアドに書いておき該当する処理でRAISERROR が発生した場合に処理を検証して特定する際に役立つ任意の数値として使うことができる。

TRY CATCH を用いたストアドプロシージャを想定した例

DECLARE @StateNum INT
DECLARE @RefString NVARCHAR(100);

    • //初期設定

SET @StateNum = 1
SET @RefString = 'XXXXXXX'

BEGIN TRY

SET @RefString = '関数処理01'
/*-----------------------------------------------
関数処理01*/

SET @StateNum = 2
/*-----------------------------------------------
関数処理02*/

SET @StateNum = 3
/*-----------------------------------------------
関数処理03 ここでエラー*/
RAISERROR ('ERROR %10.6s発生', -- メッセージID.
18, -- 重大度,
@StateNum, -- State
 @RefString -- %s に入る文字
);

END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;

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

/* CATCH したエラーをCATCH ステートメント内部で再度RAISERRORすることで
  アプリケーションにエラーとして戻すことができる*/
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);

END CATCH

上記の結果表示
※TRY CATCH を使うことによりTRYブロック内にてRAISERROR 関数のSeverity(11-18)でエラー発生させている。
 そこでアプリケーションにエラーを戻させるため、再度CATCHブロック内でRAISERRORを使っている

CATCH ブロック内のRAISERROR なしの場合は「正常」という処理で終了する。

◇まとめ
RAISERROR 関数の使い方について述べてきた、有効にオリジナルな使い方が考えられる便利な関数であり、TRY CATCH と同様ストアドプロシージャの作成に生かしてもらいたい。