データベース千夜一夜第31回

ストアドプロシージャ(5)~補足・CASE関数とエラー処理 長谷川裕行
有限会社 手國堂

エラー処理の補足~RAISERROR命令

予め規定されたエラーメッセージではなく、データベースやアプリケーションの側で独自のエラーメッセージを表示させるにはRAISERROR命令を使います。


- エラーメッセージの形式 -

データベース・エンジンに何らかのエラーが発生すると、予め規定されている重大度レベル(「sysmessages」テーブルの「severity」フィールドの値)に応じてSQL ServerのエラーログやサーバーOSのログ(アプリケーション・ログ)にメッセージが書き込まれたり、クライアントに対してエラーメッセージが送信されたりします。

クライアントに送信されるエラーメッセージ(クエリアナライザのメッセージペインに表示されるメッセージと同じもの)は、以下のような形式です。

  サーバー : メッセージ 208、レベル 16、状態 1、行 1
  オブジェクト名 '商品マスター' は無効です。

上のメッセージは、

  SELECT * FROM  商品マスター

と、データベースに存在しないテーブル「商品マスター」を指定したために発生したエラーに対するもので、208がエラー番号、16が重大度です。


- 独自のメッセージを表示させたい -

しかし、SQL Serverのエラーメッセージ(“sysmessages.description”の値)はシンプルなため、実際にユーザーが操作しているアプリケーションのレベルでは、エラーの内容が分かりにくいこともあります。また、「次になにをすれば回復できるのか」が示されないため、ユーザーを戸惑わせる要因ともなるでしょう。

前回、前々回で紹介した@@ERROR関数による処理では、

  Print '削除操作でエラーが発生しました。'

のようにPrint命令を使ってエラーメッセージを表示させていました。単純な処理ではこれでも対応できますが、やはりもの足りません。

そんな場合、RAISERROR命令が役に立ちます。


- RAISERRORの書式 -

RAISERROR命令は、SQL Server固有のエラーメッセージ(“sysmessages.description”の値)の他、プログラマー(データベース管理者)側で設定した独自のメッセージに、テーブル名や処理件数などの値を挿入してクライアントに送信できます。

RAISERROR命令の書式は以下の通りです。

RAISERROR (<メッセージID>|<メッセージ>,
<重大度レベル>,
<呼び出し状態>,
<パラメータリスト>...)

第1引数では、<メッセージID>または<メッセージ>のどちらかを指定します。メッセージIDはSQL Server既定のエラー番号(@@ERRORの戻り値)で、これを指定すれば、エラー番号に該当するエラーメッセージ(“sysmessages.description”の値)が表示されます。

<メッセージ>は''で囲んだ400文字以内の文字列で、C言語のprintf関数のように文字列中に%で始まる置換記号を挿入し、<パラメータリスト>で列挙した値に置き換えることができます。


- 置換記号 -

置換記号は接頭記号%に続けて記述します。次のような種類があります。

・書式
右寄せ、左寄せ、空白埋めなどの表示書式を指定します(表2参照)。

表2:書式指定記号
記号 機能
- 次項で示す「幅」で指定した表示桁数の枠内で左寄せに表示します。
+ 符号付きの値に対して、先頭に+(正の値の場合)または-(負の値の場合)を表示します。
0 次項で示す「幅」で指定した表示桁数の枠内で、空いている部分を0で埋めます。
# 次項で示す「変換」でxまたはXを指定して16進表示する場合に、数値の前に0xまたは0X接頭記号を追加します。
空白 次項で示す「幅」で指定した表示桁数の枠内で、空いている部分を半角のスペースで埋めます。+指定される場合には無視されます。

・幅
表示の最小桁数を整数で指定します。*を指定すると、次の「変換」で変換された数値文字列の桁数となります。

・変換
対応するパラメータの値を、10進整数、8進数、16進数などに変換して表示します(表3参照)。*を指定すると、パラメータの値で表示桁数が決まります。

表3:変換記号
記号 機能
dまたはi 符号付き整数
o 符号なし8進数
p ポインタ
s 文字列
u 符号なし整数
xまたはX 符号なし16進数

・重大度レベル
通常は0~18までの数値を指定します。20~25はSQL Serverが致命的エラーとみなし、これを受け取るとクライアントとの接続が終了して、SQL ServerとOSにエラーログが記録されます。
通常は16を指定しておけばいいでしょう。省略しても構いません。

・呼び出し状態
1~127までの値を設定します。省略しても構いません。省略すると、規定値の1が割り当てられます。

・パラメータ
<メッセージ>の中で%接頭記号を使って示された置換用の値を
. で区切って列挙します。連挙の順序と置換記号の順序が合致していなければなりません。
パラメータは20個まで指定でき、ローカル変数とint、char、varchar、binary、varbinary型の値が使えます。

例えば、int型の変数@Columnの値を「xx行目でエラーが発生しました。」という文字列のxxの箇所に表示するなら、RAISERROR関数の引数は以下のようになります。

  '%d 行目でエラーが発生しました。', @Column

@Columnの値が165であれば、表示されるメッセージは

  168行目でエラーが発生しました。

となります。

また、商品IDを保持する変数@ItemIdの値を使って「商品ID : 001053の商品は存在しません。」のように0埋め形式でID番号を表示するなら、RAISERROR関数の引数は以下のようになります。

  '商品ID : %04d の商品は存在しません。', @ItemId


- エラーメッセージの例 -

RAISERROR命令を使った例を1つ示しておきましょう。先に紹介したテーブルの転記処理“YearlyTransfer”で、処理後にデータベース名とデータベースID(データベースを一意に示す固有の識別番号)を含むメッセージを表示させます。

DB_NAMEは自身のデータベース名を返す関数、DB_IDは、自身のデータベースIDを返す関数(メタデータ関数)です。

Create Procedure YearlyTransfer5
As
DECLARE @ErrCode int -- エラー番号を保存
DECLARE @DbId -- データベースIDを保存
DECLARE @DbName nvarchar(128) -- データベース名を保存
Set @DbId = DB_ID()
Set @DbName = DB_NAME()
--
SELECT * INTO 累積売上_old FROM 累積売上_dmy
If @@ERROR = 0
Begin
DELETE 累積売上_dmy
If @@ERROR = 0
Begin
RAISERROR(
'データベース : %s(ID=%d)に対するテーブル転記処理が完了しました。',
@DbName, @Dbid)
Set @ErrCode = 0
End
Else
Begin
'データベース : %s(ID=%d)に対するテーブル削除処理が失敗しました。',
@DbName, @Dbid)
Set @ErrCode = @@ERROR
End
End
Else
Begin
'データベース : %s(ID=%d)に対するテーブルコピー処理が失敗しました。',
@DbName, @Dbid)
Set @ErrCode = @@ERROR
End
Return @ErrCode


あとがき

今回は、ストアドプロシージャの作り方そのものではなく、それに関連した関数とエラー処理について説明しました。

Case関数は、SELECT命令と組み合わせてフィールドの値を一時的に違う形式にするような場合に役に立ちます。

RAISERROR命令は、状況に応じた様々なパラメータを組み込み、分かりやすいエラーメッセージを表示する場合に役立ちます。

どちらも頻繁に利用するものではありませんが、うまく使うと扱いやすい処理を作れるでしょう。


Downloadサンプルファイル (LZH形式 459B)



トップページ
制御構造の補足~Case関数
エラー処理の補足~sysmessagesテーブル
エラー処理の補足~RAISERROR命令
エラーメッセージの形式
独自のメッセージを表示させたい
RAISERRORの書式
置換記号
エラーメッセージの例
あとがき
Copyright © MESCIUS inc. All rights reserved.