CHECK制約で複数の列の条件関係を定義する
実は、というほどでもないのですが、CASE式はCHECK制約と非常に相性が良いのです。実際にCASE式を使う局面の半分は、CHECK制約の中ではないかと思うほどです。あまりCHECK制約を使わないDBエンジニアも多いかもしれませんが、CASE式と組み合わせたときの表現力の強さを知れば、きっとすぐに利用したくなるでしょう。
例えば、ここに「女性社員の給料は20万円以下」という給与体系を持つ会社があるとします。この言語道断な会社の人事テーブルにおいて、この条件をCHECK制約で表現したのが次のSQLです。
CONSTRAINT check_salary CHECK ( CASE WHEN sex = '2' THEN CASE WHEN salary <= 200000 THEN 1 ELSE 0 END ELSE 1 END = 1 )
CASE式を入れ子にして、「社員の性別が女性ならば、給料は20万円以下である」という命題を表現しています。これは命題論理で条件法(conditional)と呼ばれる論理式で、形式的に書けば「P → Q」となります。
ここで一つ、重要なことを理解してください。それは、条件法と論理積(logical puroduct)との違いです。論理積とは「P かつ Q」を意味する論理式で形式的には「P ∧ Q」と書きます。CHECK制約で表現すると次のようになります。
CONSTRAINT check_salary CHECK ( sex = '2' AND salary <= 200000 )
この2つの制約は、もちろん異なる動作をします。では、一体どのように異なるのでしょうか? 解答と解説を次にまとめます。
解答と解説
解答
論理積のCHECK制約を付けると、この会社は男性を雇用できなくなる。条件法であれば、男性も働ける。
解説
論理積「P ∧ Q」を満たす場合は、命題Pと命題Q が共に真か、どちらかが真でもう一方が不明である場合です。つまりこの会社で働けるのは「女性であり、かつ、給料が20万円以下」の社員か、性別または給料の値が不明の社員の場合です(どちらかの条件が偽になるなら、もう片方の条件が不明な人でも働けません)。
一方、条件法「P ならば Q」を満たす場合は、PとQが共に真の場合と、Pが偽または不明な全ての場合です。
以下に両者の真理表を示すので参考にしてください。なお、U は、SQLの3値論理に特有の真理値unknownの略です(3値論理については、私のWebサイト「3値論理」を参照してください)。
| 論理積 | 条件法 | ||||
| P | Q | P ∧ Q | P | Q | P → Q |
| T | T | T | T | T | T |
| T | F | F | T | F | F |
| T | U | U | T | U | F |
| F | T | F | F | T | T |
| F | F | F | F | F | T |
| F | U | F | F | U | T |
| U | T | U | U | T | T |
| U | F | F | U | F | T |
| U | U | U | U | U | T |
見てのとおり、条件法はそもそも社員の性別が女性でない(あるいは性別が分からない)場合は真となります。その意味で、論理積よりも緩い制約であると言えます。
まとめ
今回は、CASE式の文法、および代表的な使い方を3通り紹介しました。コード体系の変換、集約関数との組み合わせ、CHECK制約との組み合わせ、いずれも非常に便利な使い道です。
次回『CASE式のススメ(後編)』では、条件分岐させたUPDATE文の書き方、CASE式の中でサブクエリを使ったテーブル間のマッチング処理、そして CASE式の中で集約関数を使って HAVING句の条件設定を SELECT句で行なう方法という、より高度な使い方を紹介します。
