NULL/CASE演習
概要
- 日程: Day 2 / セッション 6
- 時間: 13:00-13:30
- 形式: 実習
- ゴール: CASE式で給与を「高・中・低」に分類するクエリ、NULLを含むデータを正しく扱うクエリをそれぞれ書ける
- 学習形式: ハンズオン実習(AIペアプログラミング)
導入(5分)
午前中の最後に NULL と CASE を学びました。お昼ごはんを食べている間に、頭はだいぶリセットされたかもしれません。でも大丈夫、午後の最初は手を動かしながら復習する時間です。
今日の演習では、実務でよくある3つのシナリオを扱います:
- 給与ランク表示(人事担当が報告書を作るイメージ)
- 電話番号未登録の顧客抽出(マーケが正しい連絡先を補完したいイメージ)
- NULLを「未登録」と表示する整形(管理画面の見た目を整える)
どれも、現場で「あ、これ研修でやったやつだ」となるシーンです。
本編(10分)
1. 今日使うパターンのおさらい
-- パターン1: CASEで分類
CASE
WHEN 条件 THEN '高'
WHEN 条件 THEN '中'
ELSE '低'
END AS rank
-- パターン2: NULLの判定
WHERE phone IS NULL
WHERE phone IS NOT NULL
-- パターン3: NULLの置き換え
COALESCE(phone, '未登録')
2. 演習で見ておきたいこと
CASEの結果に列名(エイリアス)を付ける AS の位置、COALESCE で代替値が文字列であること、WHEREで NULL を扱うときの IS NULL の感覚——この3つを、コードを書きながら指に覚えさせるのが今日の目標です。
💬 AIに聞いてみよう
- 「CASEで4段階以上に分類するときの書き方の見本を出して」
- 「COALESCE と CASE、どちらで書くべきかの判断軸は?」
- 「NULL を含む列で件数を数えたいとき、COUNT(*) と COUNT(列名) どっち?」
実習・演習(15分)
課題
課題1: 給与ランクで分類する
employees 全員について、給与を以下の3段階に分類して表示してください。
- 高: 500,000 円以上
- 中: 400,000 円以上 500,000 円未満
- 低: それ未満
期待する列:first_name, last_name, salary, salary_rank、給与降順で並べる。
SELECT first_name,
last_name,
salary,
CASE
WHEN salary >= 500000 THEN '高'
WHEN salary >= 400000 THEN '中'
ELSE '低'
END AS salary_rank
FROM employees
ORDER BY salary DESC;
実行結果から、「高」「中」「低」がそれぞれ何人いるか数えてみてください。
課題2: ランクごとの人数を集計する
課題1のCASE式を GROUP BY と組み合わせて、ランクごとの人数を出してください。
SELECT CASE
WHEN salary >= 500000 THEN '高'
WHEN salary >= 400000 THEN '中'
ELSE '低'
END AS salary_rank,
COUNT(*) AS 人数
FROM employees
GROUP BY salary_rank
ORDER BY 人数 DESC;
課題3: 電話番号が未登録の顧客を探す
customers テーブルの phone は、サンプルデータでは全件埋まっています。まずは BEGIN してNULL を作ってみましょう。
BEGIN;
-- 1件をわざと NULL にする
UPDATE customers SET phone = NULL WHERE customer_id = 1;
-- 確認1: 等価比較は機能しない(0件になる)
SELECT customer_id, customer_name, phone
FROM customers
WHERE phone = NULL;
-- 確認2: IS NULL を使うと取れる
SELECT customer_id, customer_name, phone
FROM customers
WHERE phone IS NULL;
ROLLBACK;
「phone = NULL だと0件、IS NULL だと取れる」——この違いを目で確認するのが今日のヤマです。
課題4: NULL を「未登録」と表示する
引き続きBEGINしてphoneにNULLを作り、COALESCEで整形した一覧を作ってください。
BEGIN;
UPDATE customers SET phone = NULL WHERE customer_id IN (1, 3);
SELECT customer_id,
customer_name,
COALESCE(phone, '未登録') AS phone_display
FROM customers
ORDER BY customer_id;
ROLLBACK;
8件のうち2件が「未登録」と表示されることを確認。
課題5: CASE で書き換える
課題4と同じ結果を、COALESCE ではなく CASE 式で書いてみてください。
BEGIN;
UPDATE customers SET phone = NULL WHERE customer_id IN (1, 3);
SELECT customer_id,
customer_name,
CASE
WHEN phone IS NULL THEN '未登録'
ELSE phone
END AS phone_display
FROM customers
ORDER BY customer_id;
ROLLBACK;
「COALESCE と CASE、どちらが好みか」を考えてみてください。シンプルなら COALESCE、条件が増えるなら CASE が向いている、と感じられるはずです。
課題6(チャレンジ): 注文ステータスを日本語化する
orders.status は 'pending'、'processing'、'shipped'、'completed' のいずれかです。これを日本語に置き換えて表示してください。
SELECT order_id,
order_date,
CASE status
WHEN 'pending' THEN '未処理'
WHEN 'processing' THEN '処理中'
WHEN 'shipped' THEN '発送済'
WHEN 'completed' THEN '完了'
ELSE '不明'
END AS 状態
FROM orders
ORDER BY order_date;
CASEには上の「単純CASE」(CASE 列 WHEN 値 ...)と、CASE WHEN 条件 ... の2形式があります。今回のように値の置き換えなら単純CASEがすっきり書けます。
成果物
以下を1ファイルにまとめてください。
- 課題1〜5の実行SQLと結果(先頭5行ずつでOK)
- 課題3で
phone = NULLの結果が0件だった理由(1行で) - 課題4と課題5を比べて、自分はどちらの書き方が好きか、その理由
ヒント
- BEGIN を打ったまま課題を進めて、終わったら ROLLBACK で元に戻すのが安全
- AIに「このCASE式を日本語で順番に説明して」と頼むと、自分の理解確認になる
- CASEの条件は上から順に評価される。「高」を
salary >= 400000より先に置かないと「中」「高」が混ざる
まとめ(5分)
NULL と CASE は、データを「正直に扱い」「見やすく加工する」ための2つの基本ツールです。IS NULL/COALESCE/CASE WHEN——この3つを反射的に出せれば、レポート作成系のクエリで困ることはまずありません。
今日はDay2の前半(INSERT/UPDATE/DELETE → JOIN → NULL/CASE)が一区切りです。データを変える・つなぐ・整える、の3点セットが揃いました。
次のセッション以降では、サブクエリやビュー、テーブル設計・制約、最後にインデックスとトランザクションへと進みます。今日学んだことが、その全部の土台になります。
🔄 振り返りチェック
- なぜ
phone = NULLではダメで、IS NULLでなければならないのですか? - COALESCE と CASE はどう使い分けますか?
- CASEで分類するとき、条件の順序を間違えるとどうなりますか?
補足資料
- 参考リンク: PostgreSQL公式: 条件式
- 発展課題: 「営業部の社員だけ給与ランクを表示し、それ以外は『対象外』と出す」というクエリを書いてみる(CASEとJOINを組み合わせる)
学習ガイド
想定される質問と回答例
| 質問 | ヒント |
|---|---|
| CASEの結果を ORDER BY に使える? | 使える。ORDER BY CASE WHEN status='pending' THEN 1 ELSE 2 END のように並び順を作れる |
| ELSE を書かなかったら? | マッチしない行は NULL になる。意図せず NULL が混ざるので、明示的に書くのを推奨 |
| GROUP BY にCASEの列名(エイリアス)を書ける? | PostgreSQL では書ける(標準SQLだと位置番号や式の再記述が必要な場合あり)。エイリアスを使うとシンプル |
phone <> '03-1234-5678' で NULL の人を含めたいときは? |
WHERE phone <> '03-1234-5678' OR phone IS NULL のように OR で足す。NULLは比較に勝てないので明示的に拾う |
つまずきやすいポイント
| つまずきポイント | ヒント |
|---|---|
| CASEの条件順序を逆にして全部「中」になる | 上から順にマッチするので、厳しい条件(高)→ 緩い条件(中)→ ELSE(低)の順で書く |
WHERE phone = NULL で件数0、そして「データがない!」と勘違い |
NULL の比較は NULL になり、TRUE じゃないので WHERE から落ちる。必ず IS NULL |
CASE式に END を付け忘れる |
構文エラーで止まる。「CASE …… END AS 列名」と覚える |
| COALESCEの第2引数の型がズレる | 文字列と数値を混ぜると型エラー。NULL を文字列に置き換えるなら代替値も文字列 |