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

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

制御構造の補足~Case関数

制御構造の基本命令である、条件判断と分岐のIfと繰り返しのWhileを紹介してきました。SQLは一般的なプログラミング言語とは違い、処理構造もデータ構造もそれほど複雑ではありません。

そのため、制御構造ではこの2つを目的や状況によって使い分ければ十分です。が、もう1つ、あまり使うことはないのだけれど知っていると便利な機能を紹介しておきましょう。Case関数です。


- 値を順次比較する -

Caseは制御命令ではなく関数として備わっています。機能は「2つの値(または式)を比較し、同じだった場合に一定の値を返す」というもので、Elseを組み合わせれば式が同じでない場合に返す値も指定できます。

条件式が=に固定されたIf文を、連続して実行するような形だと思えばいいでしょう。書式は以下のようになります。

  Case <値1>
   When <値2> Then <戻り値a>
   When <値3> Then <戻り値b>
   :
   [Else <戻り値x>]
  End

<値1>をWhenに続く <値2>、<値3>……と順次比較していき、両者が同じであれば続くThen以降の<戻り値>を返します。

同じ値が存在しない場合は、Else以降に示された<戻り値x>が返されます。Elseは省略可能で、省略した場合にはNULLが返ります。

このような使い方のCase関数を、単純Case関数と呼びます。


- 単純Case関数 -

単純Case関数は、Cのswitch~caseやVisual BasicのSelect~Caseと似た使い方ができます。

SELECT命令と組み合わせると、特定のフィールドの値を一時的に違うものに変更する処理が作れます。

例えば、商品の在庫数を表示するビュー「vw在庫一覧」は画面1のような結果を返します(「vw在庫一覧」のソースはリスト1のようになっています)。この中の「仕入先」フィールドの値は「菊谷家具」「奥村陶芸」のように漢字で表示されています。これは、関連付けの元になったテーブル「仕入先_mr」にそのように記録されているためです。

そこで、一時的に仕入先名を「カナ表記の略称」にしてみましょう。リスト2のようになります。Elseの役割を紹介するため、意図的に一部の仕入先のカナ表記を省いて「該当なし」と表示されるようにしています。

実行結果は画面2のようになります。“シイレサキ =”から“End,”まででCase関数を使い、「仕入先名」フィールドの値を順次比較してカナ文字列を返すようにしています。「シイレサキ」はCase関数の結果(戻り値)に対応するフィールド名となります。



リスト1:ビュー「vw在庫一覧」のソース

SELECT 商品_mr.商品ID, 商品_mr.品名, 商品_mr.仕入単価,
商品_mr.仕入先ID, 仕入先_mr.仕入先名, 在庫_mr.在庫
FROM 在庫_mr INNER JOIN
商品_mr ON 在庫_mr.商品ID = 商品_mr.商品ID INNER JOIN
仕入先_mr ON 商品_mr.仕入先ID = 仕入先_mr.仕入先ID
ORDER BY 在庫_mr.在庫

リスト2:仕入先をカナの略称で表示させる処理(ex01.sql)

SELECT 商品ID, 品名, 仕入先名,
シイレサキ =
Case 仕入先名
When '奥村陶芸' Then 'オクムラ'
When '松宮産業' Then 'マツミヤ'
When 'タカマツ化成工業' Then 'タカマツ'
When '菊谷家具' Then 'キクタニ'
When '三星事務機' Then 'ミツボシ'
Else '該当なし'
End,
在庫
FROM vw在庫一覧
ORDER BY 商品ID


- 検索Case関数 -

もう1つ、比較元の値を必要としない検索Case関数という形式があります。

  Case
   When <条件式1> Then <戻り値a>
   When <条件式2> Then <戻り値b>
   :
   [Else <戻り値x>]
  End

検索Case関数では、Whenの次に示された<条件式>を順に評価していき、結果が「真」の場合にそれに続く <戻り値>を返します。

どの<条件式>も真でなければ、Else以降に示された<戻り値x>が返されます。Elseは省略可能で、省略した場合にはNULLが返ります。

検索Case関数では、フィールドの値を様々な演算子で比較していき、その結果ごとに異なる値を戻すことができます。

取り引き(伝票番号)ごとの商品の販売数と販売額の合計を取りまとめたビュー「vw売上明細」から、各商品の販売額が「3,000円以下なら★、5,000円以下なら★★、10,000円以下なら★★★、10,001円以上なら★★★★」という記号(文字列)を、「評価」フィールドに表示させてみましょう(「vw売上明細」のソースはリスト3のようになっています)。

実行結果は画面4のようになります。“評価=”から“End”まででCase関数を使い、When以降で「金額」フィールドの値を順次比較して「★」マークの文字列を返すようにしています。「評価」はCase関数の結果(戻り値)に対応するフィールド名となります。



リスト3:ビュー「vw売上明細」のソース

SELECT 売上明細.伝票番号, 売上明細.商品ID, 商品_mr.品名,
売上明細.数量, 売上明細.単価, 売上明細.金額
FROM 商品_mr INNER JOIN
売上明細 ON 商品_mr.商品ID = 売上明細.商品ID

リスト4:販売額に応じて「★」で評価を示す(ex02.sql)

SELECT 伝票番号, 商品ID, 品名, 数量, 単価, 金額,
評価 =
Case
When 金額 <= 3000 Then '★'
When 金額 <= 5000 Then '★★'
When 金額 <= 10000 Then '★★★'
Else '★★★★'
End
FROM vw売上明細
ORDER BY 伝票番号


- 値の一時的な変更に便利 -

このようにCase関数は、フィールドの値を元に順次比較処理を行って、その結果ごとに異なる値を、一時的に付け足したフィールドに割り当てる──といった処理で役立ちます。

比較元の値(フィールド名)を明示できる単純Case関数では比較に「等しいかどうか(=)」しか使えませんが、検索Case関数を使えば様々な比較演算が行えます。

検索Case関数を使う場合、一般的にはリスト4の例のように同じフィールドの値を次々と比較していくことになるでしょうから、ソースでは同じフィールド名を連続して記述しなければならず、見た目にはいささか冗長です。が、うまく使うと、意外に応用範囲の広い関数だということがお分かりいただけるでしょう。



トップページ
制御構造の補足~Case関数
値を順次比較する
単純Case関数
検索Case関数
値の一時的な変更に便利
エラー処理の補足~sysmessagesテーブル
エラー処理の補足~RAISERROR命令
あとがき
Copyright © MESCIUS inc. All rights reserved.