順番に読み進めながら学べます

関数 ⑤ — CASE で多条件の分岐表示

この記事は、基礎から複雑なSQL,SQLチューニングまでSQLの実践的なスキルを1からマスターする「SQL入門講座の一部」です。
CASE式の値マッチ形式と評価式形式、3つ以上の分岐、関数や複合条件、ORDER BYとの組み合わせまで、CSVの社員データで実行しながら学べます。

本記事で使うデータ — staff テーブル

前回扱ったIIFは条件式が1 つだけで、真と偽の 2 値分岐しかできませんでした。本記事のCASE 式3 つ以上の条件を順に評価して、それぞれに違う値を返せます。SQL の中で「if-elseif-else」を書くための基本構文で、レポートのカテゴリ分け・地域分け・成績ランク分けなど、実務でもっとも頻出する分岐構文です。

題材は前回までと同じstaffテーブル(10 行)です。city列で地域分類、salary列で給与帯分類、birthday列で世代分類を作る演習を通して、CASE の 2 つの書き方と複合条件への応用を順に試します。

演習に入る前に、staffテーブルの列定義データのサンプルを確認しておきます。

PRAGMA table_info(staff);で列名・型・主キーを確認してください。

SELECT * FROM staff LIMIT 5;で先頭 5 行のデータをプレビューしてください。

SQL エディタ

クエリを実行してください

CASE には 2 つの書き方がある

CASE 式には値マッチ形式評価式形式の 2 通りの書き方があり、どちらも同じ結果を作れます。両方に共通するルールが 2 つあります。

  • 最後のENDが必須 — 書き忘れると構文エラーになります。
  • ELSEは省略可能 — 省略するとどのWHENにも一致しない行がNULLになります。NULL を避けたいときはELSEでデフォルト値を明示します。

書き方 ① 値マッチ形式 — 列の値を等価比較する

値マッチ形式はCASE 列 WHEN 値1 THEN 結果1 WHEN 値2 THEN 結果2 ... ELSE デフォルト ENDと書きます。CASEの直後に比較したい列を 1 つ置き、WHENの右にはその列と等しいか調べる値を書きます。判定は等価比較(=)だけWHENの右に書けるのは1 つの値だけで、WHEN ('Tokyo', 'Osaka')のような複数指定はできません。列 = 値の単純な置き換えに向き、書き方が短くなります。

値マッチ形式の分岐
対象の列WHEN の値返る値CASE city= 'Tokyo'= 'Osaka'ELSE'東京''大阪'もとの city
CASE cityが 1 つの列を見て、各WHENの値と等価比較します。一致したWHENTHENの値が返り、どれにも一致しなければELSEの値になります。
-- 値マッチ形式 — city を地方名に置き換える
SELECT name, city,
  CASE city
    WHEN 'Tokyo' THEN '関東'
    WHEN 'Yokohama' THEN '関東'
    WHEN 'Osaka' THEN '関西'
    WHEN 'Kyoto' THEN '関西'
    ELSE 'その他'
  END AS region
FROM staff;

「社員一覧のcity列を日本語表記に置き換えて表示したい」という要件を想定します。(正しく実行できれば解説が表示されます)

staffテーブルからnamecityを取り出してください。

値マッチ形式のCASEを使い、cityが Tokyo なら東京、Osaka なら大阪、Kyoto なら京都、Yokohama なら横浜、Sapporo なら札幌、どれにも当てはまらない場合はもとのcityの値、となる列をcity_jpという別名で 3 列目に追加してください。

SQL エディタ

クエリを実行してください

書き方 ② 評価式形式 — 条件式を自由に書く

評価式形式はCASE WHEN 評価式1 THEN 結果1 WHEN 評価式2 THEN 結果2 ... ELSE デフォルト ENDと書きます。CASEの直後には何も書かず、各WHENの右に条件式そのものを置きます。salary >= 6000000比較演算子name LIKE '%Tanaka'LIKEINAND / OR複合条件など、WHERE に書ける条件はそのまま使えます。WHEN上から順に評価され、最初に TRUE になった分岐で値が確定します。表現力が高いため、実務ではこちらを主に使います。

評価式形式の分岐 — 上から順に評価
WHEN を上から評価判定返る値salary >= 6000000salary >= 4500000ELSETRUE ならTRUE なら残り全部'シニア''中堅''若手'FALSEFALSE
WHEN上から順に評価します。条件が TRUE になったらそのTHENの値で確定し、以降は評価しません。FALSE のときは次のWHENへ下がり、どれも FALSE ならELSEの値になります。
-- 評価式形式 — salary を 2 段階に分ける
SELECT name, salary,
  CASE
    WHEN salary >= 5000000 THEN '高め'
    ELSE '標準'
  END AS pay_band
FROM staff;

「給料に応じて社員を 3 段階(若手 / 中堅 / シニア)に分類したい」という要件を想定します。

staffテーブルからnamesalaryを取り出してください。

評価式形式のCASEを使い、salaryが 6,000,000 以上なら'シニア'、4,500,000 以上 6,000,000 未満なら'中堅'、それ未満なら'若手'となるラベル列をtierという別名で 3 列目に追加してください。

SQL エディタ

クエリを実行してください

関数や複合条件と組み合わせて、より複雑な分岐

CASE の WHEN 句には比較演算子・LIKE・IN・AND / OR・関数呼び出しを組み合わせた評価式を書けます。関数 ① の日付関数で学んだstrftime('%Y', birthday)で生まれ年を取り出して世代分類したり、nameは『名 姓』の並びなのでname LIKE '%Tanaka'(後方一致)で苗字が Tanaka の人を分類したり、AND複数列を組み合わせた条件を書いたりできます。

下の例では、生まれ年を 10 年単位で取り出し、1990 年代生まれを'Z 世代'、1980 年代生まれを'X/Y 世代'のようにラベル付けします。strftimeの戻り値は文字列なので、比較も文字列リテラル('1990' / '1999')と行います。

-- 1) 生まれ年を 5 年区切りでラベル付け
SELECT name, birthday,
  CASE
    WHEN strftime('%Y', birthday) BETWEEN '1985' AND '1989' THEN '1980 年代後半'
    WHEN strftime('%Y', birthday) BETWEEN '1990' AND '1994' THEN '1990 年代前半'
    ELSE 'その他'
  END AS cohort
FROM staff;

-- 2) 複合条件: 高給かつ Tokyo 在住
SELECT name, city, salary,
  CASE
    WHEN salary >= 6000000 AND city = 'Tokyo' THEN 'Tokyo シニア'
    WHEN salary >= 6000000 THEN 'シニア'
    ELSE 'その他'
  END AS tag
FROM staff;

「全社員を生まれ年で 10 年単位の世代に分けて表示したい」という要件を想定します。

staffテーブルからnamebirthdayを取り出してください。

評価式形式のCASEを使い、birthdayから取り出した生まれ年が 1990 年代なら'Z 世代'、1980 年代なら'X/Y 世代'、それ以外は'その他'となるラベル列をgenerationという別名で 3 列目に追加してください。

SQL エディタ

クエリを実行してください

「ランキング画面に給料 TOP 5 を表示し、それぞれに給与帯ラベルを併記したい」という要件を想定します。

staffテーブルからnamesalaryを取り出してください。

評価式形式のCASEで、実践 2 と同じ給与帯ラベル(salaryが 6,000,000 以上で'シニア'、4,500,000 以上で'中堅'、それ未満で'若手')をtierという別名で 3 列目に追加してください。

salaryの降順で並べ、先頭 5 行に絞ってください。

SQL エディタ

クエリを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1次のうち、CASE 式の構造として正しいものはどれですか。

Q2値マッチ形式CASE city WHEN 'Tokyo' THEN '東京' WHEN 'Osaka' THEN '大阪' ELSE city ENDの説明として正しいものはどれですか。

Q3CASE WHEN salary >= 6000000 THEN 'シニア' WHEN salary >= 4500000 THEN '中堅' ELSE '若手' ENDを salary = 7,000,000 の行に対して評価したときの結果はどれですか。