CASE 式の使い方
shain社員
| name | salary |
|---|---|
| 鈴木 | 980000 |
| 佐藤 | 720000 |
| 田中 | 520000 |
| 中村 | 530000 |
| 小林 | 445050 |
| 加藤 | 610000 |
| … | |
CASE で作った列を足す分類した結果
| name | salary | kaikyu |
|---|---|---|
| 鈴木 | 980000 | A |
| 佐藤 | 720000 | A |
| 田中 | 520000 | B |
| 中村 | 530000 | B |
| 小林 | 445050 | C |
| 加藤 | 610000 | B |
| … | ||
CASE WHEN salary >= 700000 THEN 'A' WHEN salary >= 500000 THEN 'B' ELSE 'C' END AS kaikyu
- 青い列= 式から作った列。元の表には無い列です
- 社員 18 行 → 分類した結果 18 行(行数は変わりません。減らすのは WHERE の仕事です)
行は 1 行も減っていません。CASE は「行を選ぶ」道具ではなく「値を作る」道具です。全 18 行では A が 3 人・B が 7 人・C が 8 人になります。
CASE は「値によって別の値を返す」式です。 行を絞るのではなく、元の値から新しい列を作ります。いちばん事故が多いのは 条件が上から順に評価されることで、順序を間違えると一生届かない枝ができます。
主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01書き方は 2 つある
結論: 条件を書く形(検索形)と、値を並べる形(簡単形)の 2 つです。
- 検索形 …
CASE WHEN 条件 THEN 値 … ELSE 値 END - 簡単形 …
CASE 列 WHEN 値 THEN 値 … ELSE 値 END
簡単形は「その列が○○と等しいなら」という等値比較しかできません。範囲で分けたいときは検索形を使います。
迷ったら検索形にしてください。 書ける条件が広く、あとから範囲条件を足したくなっても書き換えずに済みます。簡単形は列名を 1 回しか書かなくてよいぶん、値の対応表を書くときに読みやすくなります。
SELECT name,元の列CASE WHEN salary >= 700000 THEN 'A'上から順に判定するWHEN salary >= 500000 THEN 'B'上が偽なら次を見るELSE 'C'どれにも当てはまらないときEND AS kaikyu作った列に名前を付けるFROM shainどの表を見るか
END で閉じるのを忘れやすい部分です。AS で名前を付けないと、製品によっては列名が case のような機械的な名前になります。
SELECT name, salary,
CASE WHEN salary >= 700000 THEN 'A'
WHEN salary >= 500000 THEN 'B'
ELSE 'C'
END AS kaikyu
FROM shain
ORDER BY salary DESC;| name | salary | kaikyu |
|---|---|---|
| 鈴木 | 980000 | A |
| 佐藤 | 720000 | A |
| 山田 | 700000 | A |
| 清水 | 650000 | B |
| 加藤 | 610000 | B |
| 伊藤 | 530000 | B |
| 中村 | 530000 | B |
| 田中 | 520000 | B |
(18 行 … うち先頭 8 行を表示)
18 行そのままで、右端に列が 1 つ増えています。A が 3 人・B が 7 人・C が 8 人です。
SELECT name, busho_id,
CASE busho_id WHEN 1 THEN '経営'
WHEN 2 THEN '開発'
ELSE 'その他'
END AS busho
FROM shain
ORDER BY shain_id;| name | busho_id | busho |
|---|---|---|
| 鈴木 | 1 | 経営 |
| 佐藤 | 2 | 開発 |
| 田中 | 2 | 開発 |
| 中村 | 2 | 開発 |
| 小林 | 2 | 開発 |
| 加藤 | 5 | その他 |
(18 行 … うち先頭 6 行を表示)
列名 busho_id を 1 回しか書いていません。等値比較だけなら、こちらのほうが対応関係が読み取りやすくなります。
02⚠️ よくある間違い:上から順に評価される
結論: 最初に真になった枝で確定し、それ以降は見ません。 そのため条件の順序で結果が変わります。
範囲で分けるときは、狭いほう(厳しいほう)から書くのが鉄則です。広い条件を先に書くと、そのあとの枝には永久に届きません。
次の例は、さきほどの CASE の 1 つ目と 2 つ目を入れ替えただけです。salary >= 500000 が先に来るため、給与が 98 万の人も 72 万の人もすべて B になり、A が 1 人も出ません。
エラーは出ません。 分類の結果を数えて初めて気づくたぐいの間違いです。書いたら必ず、各区分の件数を数えて確かめてください。
SELECT name, salary,
CASE WHEN salary >= 500000 THEN 'B'
WHEN salary >= 700000 THEN 'A'
ELSE 'C'
END AS kaikyu
FROM shain
ORDER BY salary DESC;| name | salary | kaikyu |
|---|---|---|
| 鈴木 | 980000 | B |
| 佐藤 | 720000 | B |
| 山田 | 700000 | B |
| 清水 | 650000 | B |
| 加藤 | 610000 | B |
| 伊藤 | 530000 | B |
| 中村 | 530000 | B |
| 田中 | 520000 | B |
(18 行 … うち先頭 8 行を表示)
給与 980000 の鈴木まで B になっています。2 つ目の枝(A)には永久に届きません。18 行のうち A は 0 人です。
03ELSE を省略すると NULL になる
結論: どの枝にも当てはまらず ELSE も無いとき、CASE は NULL を返します。
エラーにはなりません。分類したつもりの列に NULL が並ぶので、そのあとの集計や結合で静かに行が落ちる原因になります。
ELSE は基本的に必ず書いてください。 「その他」を明示しておけば、想定外の値が入ってきたときも NULL ではなくラベルとして現れます。
逆に「当てはまらないものは NULL でよい」と分かっていて省略するのは正しい使い方です。集計と組み合わせる書き方(後述)はこれを利用しています。
SELECT name, salary,
CASE WHEN salary >= 700000 THEN '高' END AS kekka
FROM shain
ORDER BY salary DESC;| name | salary | kekka |
|---|---|---|
| 鈴木 | 980000 | 高 |
| 佐藤 | 720000 | 高 |
| 山田 | 700000 | 高 |
| 清水 | 650000 | NULL |
| 加藤 | 610000 | NULL |
| 伊藤 | 530000 | NULL |
(18 行 … うち先頭 6 行を表示)
70 万未満の 15 人は NULL になっています。「分類できなかった」ことがエラーではなく NULL で表れます。
04⚠️ よくある間違い:簡単形は NULL に一致しない
結論: CASE 列 WHEN NULL THEN … は絶対に一致しません。
簡単形の WHEN は内部で 列 = 値 の比較をしています。列 = NULL は真にならず unknown になるので、その枝は選ばれません。
「未設定なら『未設定』と出したい」と思って WHEN NULL と書いても、その行は ELSE に落ちます。エラーが出ないので、ラベルが違うことに気づきにくい部分です。
NULL を判定したいときは検索形で WHEN 列 IS NULL THEN … と書きます。 これは IS NULL を使うので正しく一致します。
SELECT name, busho_id,
CASE busho_id WHEN NULL THEN '未設定'
ELSE 'あり'
END AS hantei
FROM shain
WHERE busho_id IS NULL
ORDER BY shain_id;| name | busho_id | hantei |
|---|---|---|
| 渡辺 | NULL | あり |
| 大野 | NULL | あり |
(2 行)
取り出しているのは所属が未設定の 2 人だけなのに、判定は「あり」になっています。WHEN NULL が一致していません。
SELECT name, busho_id,
CASE WHEN busho_id IS NULL THEN '未設定'
ELSE 'あり'
END AS hantei
FROM shain
WHERE busho_id IS NULL
ORDER BY shain_id;| name | busho_id | hantei |
|---|---|---|
| 渡辺 | NULL | 未設定 |
| 大野 | NULL | 未設定 |
(2 行)
同じ 2 人が「未設定」になりました。NULL を扱うときは検索形と IS NULL の組み合わせを使ってください。
05式が書ける場所ならどこでも使える
結論: CASE は「値を返す式」なので、SELECT だけでなく ORDER BY や集約関数の中にも書けます。
使い道として特に多いのが次の 2 つです。
- 業務上の並び順を作る … 文字コード順でも五十音順でもない「決められた順」に並べたいとき、
ORDER BY CASE …で順位を作ります - 条件つきで数える …
sum(CASE WHEN 条件 THEN 1 ELSE 0 END)で「条件に当てはまる行の数」を、まとまりごとに数えられます。WHEREで絞ると他の行まで消えてしまう場面で使います
2 つ目は、全体の件数と条件つきの件数を同じ 1 回の問い合わせで並べて出せるのが利点です。
SELECT busho_name
FROM busho
ORDER BY CASE busho_name WHEN '経営' THEN 1
WHEN '開発' THEN 2
WHEN '営業' THEN 3
ELSE 9
END,
busho_id;| busho_name |
|---|
| 経営 |
| 開発 |
| 営業 |
| 管理 |
| 基盤 |
| 法務 |
| マーケ |
(7 行)
経営 → 開発 → 営業 の順に並び、残りは busho_id 順です。文字コード順とは無関係な、決められた順序を作れます。
SELECT busho_id,
count(*) AS zenin,
sum(CASE WHEN salary >= 500000 THEN 1 ELSE 0 END) AS koukyuu
FROM shain
WHERE busho_id IS NOT NULL
GROUP BY busho_id
ORDER BY busho_id;| busho_id | zenin | koukyuu |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 4 | 3 |
| 3 | 4 | 2 |
| 4 | 3 | 2 |
| 5 | 2 | 1 |
| 7 | 2 | 1 |
(6 行)
部署ごとに「全員の数」と「50 万以上の人数」が並びます。WHERE で 50 万以上に絞ってしまうと全員の数が出せません。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
ここで出てくる関数を引く
関連するトピック
- 比較演算子CASE の条件に書く比較そのものの話です。
- IS NULL簡単形が NULL に一致しない理由と、正しい書き方です。
- GROUP BY 句条件つきで数えるときに組み合わせます。
- ORDER BY 句CASE で業務上の並び順を作れます。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 条件式(CASE)一次情報・確認 2026-08-03
- SQLite: The CASE expression一次情報・確認 2026-08-03
- MySQL 8.4 リファレンスマニュアル: フロー制御関数(CASE)一次情報・確認 2026-08-03