集約関数の外でCASE式を使う
第3回では、集約関数の中にCASE式を記述することで、集約する対象を柔軟に使い分けるという技術を解説しました。今度は、ある意味でその反対をしてみましょう。すなわち、すでに集約された結果をCASE式の引数にとって分岐させます。
どういうことか、具体的に見ていきましょう。まず、第3回で使った人事テーブルから、部署ごとの人数を選択する簡単なクエリから始めます(リスト10、図7)。
これだけならごく単純な話なのですが、業務要件によっては、「2人以下の部署と、それ以上の部署を別々のグループに分けたい」ということも生じるでしょう。いわば、集約した結果に対する、さらに一段上の分岐を記述したい、ということです。
凄いことに、CASE式はこういうケースにも適用できるのです。今度は引数にCOUNT関数を取ります(リスト11、図8)。
最初にこのクエリを見たとき、少し違和感を持つ人もいるでしょう。それは、WHERE句で同じように集約関数に条件を記述しようとしてエラーになる、というSQL初心者がよく犯してしまう間違いに原因があるのでしょう。しかし落ち着いて考えれば、SELECT句では集約関数はすでに1つの定数に定まっています。だからこそ、結果は1行につき1つの値で返されています。ということは、CASE式の引数としても、1つの定数として与えられるわけですから、構文的に問題は何1つないわけです。
もっとも、このような結果の見た目を整形する処理は、本当はSQLでやるべきことではありません。ホスト言語の表示用の機能において実現すればよいことです。というのも、SQLは本来、検索のために作られた言語であるため、表示用の整形機能はそれほど充実していないからです。この例題で見たような簡単な整形であればまだ問題はないのですが、きめ細かい表示設定を行う必要が出てきたときには、SQLでは対応しきれなくなるでしょう。そのことも、頭の隅には入れておいてください。
まとめ
手続き型言語においてIF文やCASE文といった条件分岐の機能が必須であるのと同様に、SQLにおいてもCASE式は生命線の1つです。したがって、DBエンジニアはこの機能の使い方について熟知していなければなりません。またそれだけに、CASE式を使いこなせるようになることによって、SQLプログラミングでできることの幅がぐっと広がり、データベースの世界が開けていきます。この爽快感を経験してもらうことが、実は本章の一番の目的です。
それでは、主なポイントをまとめておきましょう。
- 手続き型言語で表現可能なアルゴリズムは、SQLにおいても表現可能である
- その際に基本的な重要性を持つ道具が、分岐とループ
- SQLにおける分岐は、CASE式を使って表現する。「文パラダイム」から「式パラダイム」への飛躍が理解の重要な鍵
- CASE式は、見た目が「文」に見えがちだが、実際は名前が示すとおり「式」であり、文法的には通常の列や定数、あるいは「1 + 1」のような式を記述しているのと変わらない
- それゆえ、SQLのほとんどどんなところにでも記述できる汎用性の高さが最大の魅力
SQLにおける分岐についてさらに深く学びたい方は、以下の参考文献を参照してください。
- 『プログラマのためのSQL 第2版』
(J.セルコ 著、ピアソン・エデュケーション、2001)
セルコは、米国データベース界の重鎮の一人で、特に高度なSQLプログラミング技術の解説に手腕の冴えを見せます。
本書は、中級SQLプログラミングをマスターするために必要な知識がすべて網羅された決定版の教科書です。ただし、お世辞にもあまり読みやすくはありません。「7.1 CASE式」は、CASE式についての概念的な基礎から実際の応用例まで広くカバーする必読のテキストです。セルコもこのCASE式については「SQLにとって最重要の機能である」という破格の評価を与えています。
- 『達人に学ぶ SQL徹底指南書』
(ミック 著、翔泳社、2008)
セルコの本は敷居が高くて…という方には、手前味噌ですがこちらの拙著をお薦めします。脱初級~中級入門のレベルを噛み砕いて解説しています。
私は、SQLを教える際は、必ずCASE式の話を最初に配置するようにしています。本書も、その例に漏れず、筆頭に持ってきています(「1-1. CASE式のススメ」参照)。WHEN句の中でEXISTSなどの述語と組み合わせたり、入れ子のCASE式を使うなど、本章で紹介しきれなかった重要なテクニックも紹介しています。