CodeGym /コース /SQL SELF /条件式: CASE WHEN ... THEN ... ELSE ... END

条件式: CASE WHEN ... THEN ... ELSE ... END

SQL SELF
レベル 10, レッスン 0
使用可能

たぶん、もうプログラミング言語で条件式(if-elseやswitch-caseみたいなやつ)に触れたことあるよね。SQLにも条件を扱うためのツールがあるんだ。それがCASE式。クエリの中で「もし条件が合えばこうする、違ったらああする」って判断できる。

CASE構文は、特にNULL値が入ってるデータを扱うときに超便利。シンタックスはカンタン、まるでチートシートみたい。見てみよう:

CASE
    WHEN 条件1 THEN 結果1
    WHEN 条件2 THEN 結果2
    ...
    ELSE デフォルト結果
END

ロジカルでしょ?「もしこうならこれ、違ったらあれ」って感じ。覚えやすいよ。「WHEN=もし、THEN=何する、ELSE=どれも違ったらどうする」ってノリ。

例: 商品の分類

たとえばproductsテーブルがあって、priceカラムがあるとする。その値で商品をグループ分けしたいとき。

id name price
1 Magic Wand 120
2 Potion Set 45
3 Crystal Ball 75
4 Enchanted Map NULL
5 Broomstick 99
6 Spell Book 180
SELECT
    name AS product_name,
    price,
    CASE
        WHEN price IS NULL THEN '不明'
        WHEN price < 50 THEN 'お手頃'
        WHEN price BETWEEN 50 AND 100 THEN '標準'
        ELSE 'プレミアム'
    END AS price_category
FROM products;

ここで何が起きてる?

  1. 商品のpriceがNULLなら、カテゴリは'不明'になる。
  2. 価格が50未満なら「お手頃」'お手頃'。
  3. 50~100なら「標準」'標準'。
  4. それ以外は「プレミアム」'プレミアム'。

結果はこんな感じ:

product_name price price_category
Magic Wand 120 プレミアム
Potion Set 45 お手頃
Crystal Ball 75 標準
Enchanted Map NULL 不明
Broomstick 99 標準
Spell Book 180 プレミアム

SQLはまるで魔法使いみたいにproductsテーブルの行を読んで、1つずつうまく分類してくれる。

CASE WHENでNULLを扱う

データに抜けがある(やあ、NULL!)ことはよくあるし、何かで埋めたいことも多い。たとえばusersテーブルにemailカラムがあって、メールアドレスがないユーザーには'未設定'って表示したい場合。

user_id name email
1 Alex Lin alex@example.com
2 Maria Chi NULL
3 Anna Song anna@magic.com
4 Otto Art NULL
5 John Smith john@wizard.org
SELECT
    user_id,
    name,
    CASE
        WHEN email IS NULL THEN '未設定'
        ELSE email
    END AS email_address
FROM users;
user_id name email_address
1 Alex Lin alex@example.com
2 Maria Chi 未設定
3 Anna Song anna@magic.com
4 Otto Art 未設定
5 John Smith john@wizard.org

SQLはここでシャーマンみたいに、半分空っぽの行を生き返らせてくれる。emailがなければ'未設定'に、あればそのまま。

数字を使った条件式

値の置き換えだけじゃなく、新しいロジックを作りたいときもある。たとえばstudentsテーブルにscore(点数)とnameカラムがある場合。

name score
Alex Lin 95
Maria Chi 82
Anna Song 48
Otto Art NULL
John Smith 67
Zoe Black 30

学生を「優秀」「合格」「不合格」みたいに点数で評価したいとき。

SELECT
    name AS student_name,
    score,
    CASE
        WHEN score IS NULL THEN '点数なし'
        WHEN score >= 90 THEN '優秀'
        WHEN score >= 50 THEN '合格'
        ELSE '不合格'
    END AS performance_category
FROM students;
student_name score performance_category
Alex Lin 95 優秀
Maria Chi 82 合格
Anna Song 48 不合格
Otto Art NULL 点数なし
John Smith 67 合格
Zoe Black 30 不合格

SQLは厳しい試験官みたいに学生を振り分けてくれる。90点以上は「優秀」、50点以上は「合格」。足りなければ…まあ、わかるよね。

グループ化とNULLの処理

データのグループ化もCASE WHENが大活躍。たとえばordersテーブルで、NULLステータスも含めて注文数を数えたいとき。

order_id status
1 Completed
2 Pending
3 NULL
4 Shipped
5 Completed
6 NULL
7 Pending
8 Completed
9 Shipped
10 NULL
SELECT
    CASE
        WHEN status IS NULL THEN 'ステータスなし'
        ELSE status
    END AS order_status,
    COUNT(*)
FROM orders
GROUP BY 
    CASE
        WHEN status IS NULL THEN 'ステータスなし'
        ELSE status
    END;

このクエリはNULLの空ステータスを'ステータスなし'に置き換えて、各グループの注文数を数えてくれる。結果はこんな感じ:

order_status count
Completed 3
Pending 2
Shipped 2
ステータスなし 3

実践ケース:「CASE WHEN」のトリック

例1: NULLを考慮したソート

ときどきNULL値をリストの最初や最後に表示したいことがある。たとえばタスク一覧で、優先度が高いものを上に、優先度なし(NULL)は下にしたい場合とか。

task_id task_name priority
1 Fix bugs 1
2 Update documentation 3
3 Plan sprint NULL
4 Code review 2
5 Organize meeting NULL
6 Deploy release 1
SELECT
    task_name,
    priority,
    CASE
        WHEN priority IS NULL THEN 1
        ELSE 0
    END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;

ここでは「仮想」カラムpriority_sortを追加して、NULL値を一番下に、それ以外は昇順で並べてる。

task_name priority priority_sort
Deploy release 1 0
Fix bugs 1 0
Code review 2 0
Update documentation 3 0
Plan sprint NULL 1
Organize meeting NULL 1

例2: NULLを考慮した計算

今度はordersテーブルで、discountカラムがNULL(割引なし)かもしれない場合の合計金額計算。

order_id total_price discount
101 100 10
102 200 NULL
103 150 15
104 120 NULL
105 80 5

NULLは0に置き換えて計算が壊れないようにする。

SELECT 
    order_id,
    total_price,
    discount,
    total_price - 
    CASE
        WHEN discount IS NULL THEN 0
        ELSE discount
    END AS final_price
FROM orders;
order_id total_price discount final_price
101 100 10 90
102 200 NULL 200
103 150 15 135
104 120 NULL 120
105 80 5 75

このCASEの魔法トリックで、NULLが計算を壊す心配なし!

orderid = 101: discount = 10. finalprice = 100 - 10 = 90。orderid = 102: discount = NULL。CASEは0を返す。finalprice = 200 - 0 = 200。orderid = 103: discount = 15. finalprice = 150 - 15 = 135。orderid = 104: discount = NULL。CASEは0を返す。finalprice = 120 - 0 = 120。orderid = 105: discount = 5. finalprice = 80 - 5 = 75。

例3: ユーザーステータスの表示

日常的によくあるのが、ユーザーのステータス(たとえば「アクティブ」や「待機中」)やデータなしを表示したいケース。たとえばusersテーブルにlast_login(最終ログイン日)がある場合。

user_id name last_login
1 Alex Lin 2024-12-10
2 Maria Chi 2025-04-20
3 Anna Song NULL
4 Otto Art 2025-05-01
5 Liam Park 2025-05-25
SELECT
    user_id,
    name,
    CASE
        WHEN last_login IS NULL THEN '一度もログインなし'
        WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN '非アクティブ'
        ELSE 'アクティブ'
    END AS user_status
FROM users;

このクエリで管理画面が生き生きする。ログイン履歴なしは「一度もログインなし」、長期間ログインしてない人は「非アクティブ」、それ以外は「アクティブ」!

user_id name user_status
1 Alex Lin 非アクティブ
2 Maria Chi 非アクティブ
3 Anna Song 一度もログインなし
4 Otto Art 非アクティブ
5 Liam Park アクティブ

よくあるミスとその回避法

ELSEの書き忘れ: ELSEを書かないと、どの条件にも当てはまらなかったときSQLはNULLを返す。それってたぶん望んでないよね。だから全部カバーしたつもりでもELSEは明示的に書こう。

CASE
    WHEN condition THEN result
    -- ELSE 'デフォルト値' -- 忘れずに!
END

カッコなしの複雑な条件: ANDやOR、NOTを複数使うときは必ずカッコを使おう。カッコなしだとクエリが「勘違い」しちゃうかも。

CASE
    WHEN (column1 IS NOT NULL AND column2 > 5) THEN '有効'
    ELSE '無効'
END

NULLの扱い: NULLは何かと等しくなることは絶対にない(=はダメ)。たとえば:

CASE
    WHEN column = NULL THEN 'ダメ!' -- エラー!
    WHEN column IS NULL THEN '正解!' -- これが正しい。
END
2
タスク
SQL SELF, レベル 10, レッスン 0
ロック未解除
欠損データの条件付き表示
欠損データの条件付き表示
2
タスク
SQL SELF, レベル 10, レッスン 0
ロック未解除
数値に基づくカテゴリの割り当て
数値に基づくカテゴリの割り当て
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION