SQLのCASE式とは?switch相当の条件分岐を実例で解説
CONTENTS
- 1 SQLのCASE式とは?switch文のように条件分岐できるSQL構文
- 2 CASE式の基本構文
- 3 単純CASE式:switch文に近い書き方
- 4 検索CASE式:複雑な条件分岐に使う書き方
- 5 CASE式は上から順に評価される
- 6 SELECT句でCASE式を使う基本例
- 7 CASE式と集計関数を組み合わせる
- 8 CASE式でLIKEを使う方法
- 9 CASE式でINを使う方法
- 10 CASE式でAND・ORを使う方法
- 11 WHERE句でCASE式を使う方法
- 12 ORDER BY句でCASE式を使う方法
- 13 UPDATE文でCASE式を使う方法
- 14 CASE式で値を入れ替える方法
- 15 CASE式でNULLを扱うときの注意点
- 16 ELSEを省略した場合の挙動
- 17 CASE式で返す値の型をそろえる
- 18 CASE式を入れ子にする方法
- 19 CASE式とCOALESCE・NULLIFの使い分け
- 20 CASE式を使うときの実務上のよくある失敗
- 21 DBMSごとのCASE式の違い
- 22 CASE式を読みやすく書くためのポイント
- 23 CASE式の実務的な使い分け
- 24 CASE式を学ぶとSQLの実務力が上がる理由
- 25 まとめ:SQLのCASE式は条件分岐・集計・更新で役立つ実務必須の構文
SQLで「条件によって表示する値を変えたい」「statusの値に応じてラベルを出したい」「点数や金額をランク分けしたい」と思ったとき、プログラミング言語のswitch文やif文のように使えるのがCASE式です。
CASE式を使えるようになると、SELECT結果の加工、条件付き集計、ORDER BYでの任意順ソート、UPDATEでの一括更新などをSQL内で完結できます。アプリ側で分岐処理を書かなくても、データベース側で「データの意味づけ」まで行えるため、実務でも非常に使用頻度の高い構文です。
この記事では、SQLのCASE式について、基本構文からSELECT・WHERE・ORDER BY・UPDATEでの使い方、NULLやELSEの注意点、実務で読みやすく保守しやすい書き方まで解説します。元記事の内容をもとに、実務向けの観点を加えて整理しています。
SQLのCASE式とは?switch文のように条件分岐できるSQL構文
SQLのCASE式とは、条件に応じて返す値を切り替えるための式です。
プログラミング言語でいうと、if文やswitch文に近い役割を持ちます。ただし、SQLのCASEは「処理の流れを分岐する命令」というより、条件に応じて1つの値を返す式として使う点が重要です。
たとえば、次のような場面で使われます。
SELECT
user_name,
CASE status
WHEN 1 THEN '有効'
WHEN 2 THEN '停止中'
WHEN 3 THEN '退会済み'
ELSE '不明'
END AS status_label
FROM users;
このSQLでは、status の値に応じて、画面表示用のラベルを作っています。
status = 1 なら「有効」、status = 2 なら「停止中」、どれにも当てはまらない場合は「不明」を返します。
PostgreSQLの公式ドキュメントでも、CASEは「条件が真の場合に対応する結果を返し、以降のWHENは処理されない」条件式として説明されています。公式情報を確認する場合は、PostgreSQLのConditional Expressionsが参考になります。
https://www.postgresql.org/docs/current/functions-conditional.html
CASE式でできること
CASE式を使うと、SQL内で次のような処理ができます。
・コード値を表示用の文字列に変換する
・点数や金額をランク分けする
・条件に合うデータだけを集計する
・特定の条件を優先して並び替える
・UPDATE時に条件ごとに更新値を変える
・NULLや未設定値を別の文言に置き換える
つまりCASE式は、単なる「SQLの小技」ではなく、データを業務上わかりやすい形に変換するための基本構文です。
実務では、管理画面、検索結果、レポート、バッチ処理、データ移行、集計SQLなど、さまざまな場面で使われます。
CASE式は「文」ではなく「式」として理解する
CASE式を理解するうえで大切なのは、CASEが値を返す式であるという点です。
そのため、値を書ける場所であれば、さまざまな句に記述できます。
SELECT句
WHERE句
ORDER BY句
GROUP BY句
HAVING句
UPDATEのSET句
SQL Serverの公式ドキュメントでも、CASEはSELECT、UPDATE、DELETE、SETなどの文や、SELECTリスト、WHERE、ORDER BY、HAVINGなど、式を許可する場所で使用できると説明されています。
https://learn.microsoft.com/ja-jp/sql/t-sql/language-elements/case-transact-sql?view=sql-server-ver17
CASE式の基本構文
CASE式には、大きく分けて2つの書き方があります。
1つ目は、特定の列や値を比較する単純CASE式。
2つ目は、条件式を自由に書ける検索CASE式です。
どちらも最終的には「条件に一致したらTHENの値を返す」という点は同じですが、使いどころが異なります。
単純CASE式:switch文に近い書き方
単純CASE式は、1つの列や式を基準にして、値が一致するかどうかで分岐します。
基本構文は次のとおりです。
CASE 比較対象
WHEN 値1 THEN 結果1
WHEN 値2 THEN 結果2
WHEN 値3 THEN 結果3
ELSE デフォルト値
END
たとえば、会員区分コードを表示名に変換する場合は次のように書けます。
SELECT
user_id,
user_name,
CASE member_type
WHEN 'free' THEN '無料会員'
WHEN 'standard' THEN '通常会員'
WHEN 'premium' THEN 'プレミアム会員'
ELSE '未設定'
END AS member_type_label
FROM users;
この書き方は、プログラミング言語のswitch文に近く、コード値の変換に向いています。
単純CASE式が向いている場面
単純CASE式は、次のような場面で使いやすいです。
・ステータスコードを文言に変換する
・区分値をラベルに変換する
・固定のコード体系を画面表示用に整える
・都道府県コード、会員ランク、申請状態などを分類する
たとえば、申請ステータスを表示するSQLは次のようになります。
SELECT
application_id,
CASE status
WHEN 0 THEN '下書き'
WHEN 1 THEN '申請中'
WHEN 2 THEN '承認済み'
WHEN 3 THEN '差し戻し'
ELSE '不明'
END AS status_name
FROM applications;
単純CASE式は見た目がシンプルで、変換表のように読めるため、レビューしやすいのがメリットです。
単純CASE式の注意点
単純CASE式でできるのは、基本的に等価比較です。
つまり、次のような複雑な条件には向いていません。
・80点以上ならA
・金額が1万円以上なら高額
・日付が今日以降なら有効
・statusが1かつ期限切れでない場合
・nameに特定文字列を含む場合
このような条件を書きたい場合は、次に紹介する検索CASE式を使います。
検索CASE式:複雑な条件分岐に使う書き方
検索CASE式は、WHENの後ろに条件式を直接書く形式です。
基本構文は次のとおりです。
CASE
WHEN 条件1 THEN 結果1
WHEN 条件2 THEN 結果2
WHEN 条件3 THEN 結果3
ELSE デフォルト値
END
たとえば、点数に応じて評価ランクを付ける場合は次のように書けます。
SELECT
student_name,
score,
CASE
WHEN score >= 90 THEN 'S'
WHEN score >= 80 THEN 'A'
WHEN score >= 70 THEN 'B'
WHEN score >= 60 THEN 'C'
ELSE 'D'
END AS grade
FROM exam_results;
このSQLでは、score の値に応じてランクを返しています。
検索CASE式では、>=、<=、AND、OR、LIKE、IN、IS NULL などを自由に使えるため、実務ではこちらの形式を使う場面が多くなります。
検索CASE式が向いている場面
検索CASE式は、次のような条件分岐に向いています。
・点数や金額の範囲判定
・日付による有効/期限切れ判定
・複数カラムを組み合わせた条件判定
・NULLかどうかの判定
・文字列の部分一致による分類
・複数条件をまとめた業務ルールの表現
たとえば、注文金額に応じて購入ランクを付ける場合は次のように書けます。
SELECT
order_id,
customer_id,
total_amount,
CASE
WHEN total_amount >= 100000 THEN 'プラチナ'
WHEN total_amount >= 50000 THEN 'ゴールド'
WHEN total_amount >= 10000 THEN 'シルバー'
ELSE '通常'
END AS customer_rank
FROM orders;
このように、検索CASE式は「業務上の判断基準」をSQLに落とし込むときに便利です。
CASE式は上から順に評価される
CASE式で非常に重要なのが、WHENは上から順に評価されるという点です。
最初に条件が一致したWHENのTHENが返され、それ以降のWHENは評価されません。
たとえば、次のSQLには問題があります。
SELECT
score,
CASE
WHEN score >= 60 THEN '合格'
WHEN score >= 80 THEN '優秀'
ELSE '不合格'
END AS result
FROM exam_results;
一見すると、80点以上なら「優秀」になりそうですが、実際には80点以上も score >= 60 に当てはまるため、先に「合格」と判定されます。
正しく書くなら、より限定的な条件を先に書きます。
SELECT
score,
CASE
WHEN score >= 80 THEN '優秀'
WHEN score >= 60 THEN '合格'
ELSE '不合格'
END AS result
FROM exam_results;
Oracleの公式ドキュメントでも、CASE式はIF...THEN...ELSEのようなロジックをSQL文内で使えるものとして説明されています。条件の順序が結果に影響するため、範囲条件では特に注意が必要です。
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CASE-Expressions.html
SELECT句でCASE式を使う基本例
CASE式の最も基本的な使い方は、SELECT句で結果列を作る方法です。
元のデータは変更せず、検索結果として表示する値だけを条件に応じて変換できます。
ステータスコードを表示用ラベルに変換する
SELECT
id,
title,
CASE status
WHEN 1 THEN '公開中'
WHEN 2 THEN '下書き'
WHEN 3 THEN '非公開'
ELSE '不明'
END AS status_label
FROM articles;
このように書くと、データベース上では数値で管理しているステータスを、画面やレポート上では分かりやすい文言に変換できます。
アプリケーション側で毎回変換処理を書く必要がなくなるため、表示揺れを防ぎやすくなります。
条件に応じてフラグを付ける
CASE式は、0/1のフラグを作るときにも便利です。
SELECT
user_id,
user_name,
last_login_at,
CASE
WHEN last_login_at >= CURRENT_DATE - INTERVAL '7 days' THEN 1
ELSE 0
END AS is_recent_login
FROM users;
この例では、直近7日以内にログインしたユーザーに 1 を付けています。
フラグ化しておくと、アプリ側で「最近ログインしたユーザーだけ強調表示する」といった処理がしやすくなります。
金額や点数をランク分けする
SELECT
product_id,
product_name,
price,
CASE
WHEN price >= 100000 THEN '高価格帯'
WHEN price >= 30000 THEN '中価格帯'
ELSE '低価格帯'
END AS price_range
FROM products;
金額や点数のような連続値を、業務上扱いやすい区分に変換できます。
このとき大切なのは、境界値を明確にすることです。
たとえば、30,000円を中価格帯に含めるのか、低価格帯に含めるのかをSQL上で明確にしておく必要があります。
CASE式と集計関数を組み合わせる
CASE式は、SUMやCOUNTなどの集計関数と組み合わせると非常に強力です。
特に、条件ごとの件数や金額を1つのSQLで横並びに集計したい場合によく使われます。
SUMとCASEで条件別件数を集計する
SELECT
COUNT(*) AS total_count,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS stopped_count,
SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) AS withdrawn_count
FROM users;
このSQLでは、全ユーザー数に加えて、ステータス別の件数を同時に取得しています。
CASE WHEN 条件 THEN 1 ELSE 0 END によって、条件に合う行だけを1として扱い、SUMで合計しています。
COUNTとCASEを使う場合の注意点
COUNTとCASEを組み合わせることもできます。
SELECT
COUNT(CASE WHEN status = 1 THEN 1 END) AS active_count
FROM users;
このSQLでは、status = 1 の場合だけ 1 を返し、それ以外はNULLになります。COUNTはNULLを数えないため、有効ユーザー数だけを数えられます。
ただし、初心者には次のようにSUMで1/0を明示する書き方の方が分かりやすいです。
SELECT
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS active_count
FROM users;
実務では、読み手が誤解しにくいSQLを書くことも大切です。
条件別の売上合計を出す
SELECT
SUM(CASE WHEN payment_method = 'credit_card' THEN amount ELSE 0 END) AS credit_card_sales,
SUM(CASE WHEN payment_method = 'bank_transfer' THEN amount ELSE 0 END) AS bank_transfer_sales,
SUM(CASE WHEN payment_method = 'convenience_store' THEN amount ELSE 0 END) AS convenience_store_sales
FROM orders;
このように、条件に一致した金額だけを合計すれば、支払い方法別の売上を1回のSQLで取得できます。
レポート画面やダッシュボードでよく使われるパターンです。
CASE式でLIKEを使う方法
文字列の一部に特定のキーワードが含まれているかどうかで分類したい場合は、CASE式の中でLIKEを使えます。
SELECT
product_name,
CASE
WHEN product_name LIKE '%ノートPC%' THEN 'パソコン'
WHEN product_name LIKE '%マウス%' THEN '周辺機器'
WHEN product_name LIKE '%キーボード%' THEN '周辺機器'
ELSE 'その他'
END AS product_category
FROM products;
このSQLでは、商品名に含まれる文字列からカテゴリを判定しています。
LIKEを使うときの注意点
LIKEは便利ですが、前方に % を付ける検索は、データベースによってはインデックスを活かしにくくなる場合があります。
LIKE '%キーワード%'
このような部分一致検索は、大量データでは処理が重くなる可能性があります。
少量データや一時的な分類には便利ですが、継続的に使う業務ロジックであれば、次のような方法も検討すべきです。
・カテゴリ列を別途持つ
・分類マスタを作ってJOINする
・検索用の正規化済みカラムを用意する
・全文検索機能を利用する
CASE式は便利ですが、すべてをCASEで解決しようとすると、後から保守が難しくなることがあります。
CASE式でINを使う方法
複数の値をまとめて判定したい場合は、INを使うとSQLを短く書けます。
SELECT
prefecture,
CASE
WHEN prefecture IN ('東京都', '神奈川県', '千葉県', '埼玉県') THEN '関東'
WHEN prefecture IN ('大阪府', '京都府', '兵庫県', '奈良県') THEN '関西'
ELSE 'その他'
END AS area
FROM users;
このように、複数の候補を1つのWHENにまとめられるため、同じTHENを何度も書かずに済みます。
INでまとめるべき条件とマスタ化すべき条件
INは、候補が少なく、変更頻度が低い場合に向いています。
一方で、次のような条件はCASE式に直接書くより、マスタテーブルを作る方が安全です。
・分類対象が多い
・頻繁に追加、変更される
・複数のSQLで同じ分類を使う
・管理画面から変更したい
・業務部門が分類ルールを管理する
たとえば都道府県と地方の対応は、CASE式で書くこともできますが、複数箇所で使うなら prefecture_area_master のようなマスタテーブルを用意してJOINした方が保守しやすくなります。
CASE式でAND・ORを使う方法
検索CASE式では、ANDやORを使って複数条件を組み合わせられます。
SELECT
user_id,
user_name,
status,
expired_at,
CASE
WHEN status = 1 AND expired_at >= CURRENT_DATE THEN '利用可能'
WHEN status = 1 AND expired_at < CURRENT_DATE THEN '期限切れ'
WHEN status = 2 THEN '停止中'
ELSE '不明'
END AS account_status
FROM users;
このSQLでは、ステータスだけでなく、期限日も組み合わせてアカウント状態を判定しています。
実務の条件分岐では、1つの列だけで判断できるケースは少なく、複数カラムを組み合わせることがよくあります。
ORを使うときは括弧で条件を明確にする
ORを含む条件は、意図しない判定になりやすいため、括弧を使って読みやすくすることが重要です。
CASE
WHEN status = 1 AND (role = 'admin' OR role = 'manager') THEN '管理権限あり'
ELSE '一般'
END
括弧を使わないと、ANDとORの優先順位を読み手が誤解する可能性があります。
SQLは自分だけが読むものではありません。チーム開発では、後から読む人が安全に理解できる書き方を意識することが大切です。
WHERE句でCASE式を使う方法
CASE式はWHERE句でも使えます。
たとえば、検索モードによって条件を切り替えるようなSQLです。
SELECT
*
FROM orders
WHERE
CASE
WHEN :search_mode = 'paid' AND payment_status = 'paid' THEN 1
WHEN :search_mode = 'unpaid' AND payment_status = 'unpaid' THEN 1
WHEN :search_mode = 'all' THEN 1
ELSE 0
END = 1;
このSQLでは、:search_mode の値によって検索条件を切り替えています。
WHERE句のCASEは多用しすぎない
WHERE句にCASE式を書くと、SQLを1本にまとめられる一方で、読みにくくなったり、インデックスが効きにくくなったりする場合があります。
実務では、次のような選択肢も比較します。
・条件ごとにSQLを分ける
・アプリ側でWHERE条件を組み立てる
・OR条件で表現する
・動的SQLを使う
・検索条件用のビューや中間テーブルを作る
CASE式は便利ですが、「SQLを1本にまとめること」が目的になってはいけません。読みやすさ、性能、保守性を含めて判断する必要があります。
ORDER BY句でCASE式を使う方法
ORDER BY句にCASE式を使うと、任意の優先順位で並び替えできます。
たとえば、申請一覧を「要対応」「確認中」「完了」の順に表示したい場合です。
SELECT
application_id,
title,
status
FROM applications
ORDER BY
CASE status
WHEN 'waiting' THEN 1
WHEN 'checking' THEN 2
WHEN 'completed' THEN 3
ELSE 9
END,
created_at DESC;
このSQLでは、データ上のstatus値の昇順ではなく、業務上見せたい順番で並び替えています。
任意順ソートでCASE式が役立つ場面
ORDER BYのCASE式は、次のような場面で役立ちます。
・重要なステータスを先頭に出したい
・未対応データを上に表示したい
・特定カテゴリを優先表示したい
・NULLや未設定データを最後に回したい
・業務上の表示順とコード順が一致しない
たとえば、NULLの値を最後に並べたい場合は次のように書けます。
SELECT
user_id,
user_name,
last_login_at
FROM users
ORDER BY
CASE WHEN last_login_at IS NULL THEN 1 ELSE 0 END,
last_login_at DESC;
このSQLでは、ログイン日時がNULLのユーザーを最後に回し、ログイン済みユーザーは新しい順に並べています。
UPDATE文でCASE式を使う方法
CASE式はSELECTだけでなく、UPDATE文でも使えます。
条件に応じて更新値を変えたい場合に便利です。
UPDATE users
SET member_rank =
CASE
WHEN total_purchase_amount >= 100000 THEN 'platinum'
WHEN total_purchase_amount >= 50000 THEN 'gold'
WHEN total_purchase_amount >= 10000 THEN 'silver'
ELSE 'normal'
END;
このSQLでは、累計購入金額に応じて会員ランクを一括更新しています。
UPDATEでCASE式を使うメリット
UPDATEでCASE式を使うメリットは、複数の更新処理を1回にまとめられることです。
たとえば、次のような処理を別々のUPDATEで実行すると、更新順序によって意図しない結果になる場合があります。
UPDATE users SET rank = 'gold' WHERE amount >= 50000;
UPDATE users SET rank = 'platinum' WHERE amount >= 100000;
この程度なら問題になりにくいですが、条件が複雑になると、先に更新した値を後のUPDATEが上書きする可能性があります。
CASE式を使えば、元の値に基づいて1回のUPDATEで判定できます。
UPDATEで事故を防ぐ書き方
UPDATEでCASE式を使う場合は、必ず次の2点を意識します。
・WHERE句で更新対象を絞る
・ELSEで既存値を保持する
たとえば、一部のステータスだけを置き換える場合は次のように書きます。
UPDATE orders
SET status =
CASE
WHEN status = 'new' THEN '受付済み'
WHEN status = 'processing' THEN '処理中'
ELSE status
END
WHERE status IN ('new', 'processing');
ELSE status を書いておくことで、想定外の値を誤ってNULLにするリスクを減らせます。
また、WHERE句で対象を絞ることで、不要な行まで更新してしまう事故を防げます。
UPDATE前にSELECTで確認する
実務では、いきなりUPDATEを実行するのではなく、同じCASE式をSELECTで確認してから実行するのが安全です。
SELECT
order_id,
status AS before_status,
CASE
WHEN status = 'new' THEN '受付済み'
WHEN status = 'processing' THEN '処理中'
ELSE status
END AS after_status
FROM orders
WHERE status IN ('new', 'processing');
このSELECTで更新前後の値を確認し、問題がなければUPDATEを実行します。
本番データを扱う現場では、この一手間が非常に重要です。
CASE式で値を入れ替える方法
CASE式は、値の入れ替えにも使えます。
たとえば、AとBを入れ替える場合、UPDATEを2回に分けると値が潰れる可能性があります。
UPDATE sample_table
SET type =
CASE
WHEN type = 'A' THEN 'B'
WHEN type = 'B' THEN 'A'
ELSE type
END
WHERE type IN ('A', 'B');
このようにCASE式を使えば、元の値を見ながら1回で安全に入れ替えられます。
CASE式でNULLを扱うときの注意点
CASE式でよくあるミスが、NULLの判定です。
SQLでは、NULLを = NULL で判定してはいけません。
誤った例は次のとおりです。
CASE
WHEN deleted_at = NULL THEN '未削除'
ELSE '削除済み'
END
正しくは、IS NULL を使います。
CASE
WHEN deleted_at IS NULL THEN '未削除'
ELSE '削除済み'
END
NULLは「値がない」「不明」を表す特別な状態です。そのため、通常の等価比較では期待どおりに判定できません。
MySQLの公式ドキュメントでも、CASE式は最初に真となった比較または条件の結果を返し、ELSEがない場合はNULLを返すと説明されています。CASE operatorとストアドプログラム内のCASE statementは構文が異なる点も、MySQLでは確認しておきたいポイントです。
https://dev.mysql.com/doc/refman/8.0/ja/flow-control-functions.html
ELSEを省略した場合の挙動
CASE式では、ELSEを省略できます。
ただし、どのWHENにも一致しない場合はNULLが返ります。
SELECT
user_id,
CASE
WHEN status = 1 THEN '有効'
WHEN status = 2 THEN '停止中'
END AS status_label
FROM users;
このSQLでは、status が1でも2でもない場合、status_label はNULLになります。
ELSEは基本的に明示する
実務では、ELSEを明示することをおすすめします。
SELECT
user_id,
CASE
WHEN status = 1 THEN '有効'
WHEN status = 2 THEN '停止中'
ELSE '不明'
END AS status_label
FROM users;
ELSEを書くことで、想定外の値が来たときの扱いが明確になります。
特に、画面表示やCSV出力、帳票、集計処理では、NULLが混ざると後続処理に影響する場合があります。
CASE式で返す値の型をそろえる
CASE式では、THENやELSEで返す値の型をできるだけそろえることが重要です。
避けたい例は次のようなSQLです。
CASE
WHEN status = 1 THEN '有効'
WHEN status = 2 THEN 0
ELSE NULL
END
このSQLでは、文字列、数値、NULLが混在しています。
データベースによっては暗黙的な型変換が行われたり、意図しないエラーや表示崩れにつながったりする可能性があります。
次のように、返す値の型を文字列にそろえる方が安全です。
CASE
WHEN status = 1 THEN '有効'
WHEN status = 2 THEN '停止中'
ELSE '不明'
END
集計用のフラグであれば、数値にそろえます。
CASE
WHEN status = 1 THEN 1
ELSE 0
END
CASE式を入れ子にする方法
CASE式の中に、さらにCASE式を書くこともできます。
SELECT
user_id,
CASE
WHEN user_type = 'corporate' THEN
CASE
WHEN contract_count >= 10 THEN '大口法人'
ELSE '法人'
END
WHEN user_type = 'individual' THEN '個人'
ELSE '不明'
END AS user_category
FROM users;
このように、まずユーザー種別で分け、その中でさらに契約数に応じて分類できます。
入れ子のCASE式は読みづらくなりやすい
ただし、CASE式の入れ子は読みづらくなりやすいため、多用は避けるべきです。
深い入れ子になりそうな場合は、次の方法を検討します。
・CTEで中間結果を作る
・サブクエリで分類を分ける
・マスタテーブルに切り出す
・アプリケーション側のロジックに分担する
たとえば、CTEを使うと段階的に読めます。
WITH user_base AS (
SELECT
user_id,
user_type,
contract_count,
CASE
WHEN user_type = 'corporate' THEN '法人'
WHEN user_type = 'individual' THEN '個人'
ELSE '不明'
END AS base_category
FROM users
)
SELECT
user_id,
CASE
WHEN base_category = '法人' AND contract_count >= 10 THEN '大口法人'
ELSE base_category
END AS user_category
FROM user_base;
SQLは短ければよいわけではありません。保守しやすい形に分けることも、実務では重要です。
CASE式とCOALESCE・NULLIFの使い分け
CASE式と似た用途で使われる関数に、COALESCEやNULLIFがあります。
PostgreSQLの公式ドキュメントでは、CASEと同じConditional Expressionsの章で、COALESCE、NULLIF、GREATEST、LEASTなども紹介されています。
https://www.postgresql.org/docs/current/functions-conditional.html
COALESCEはNULLの代替値に使う
COALESCEは、最初にNULLでない値を返す関数です。
SELECT
user_name,
COALESCE(nickname, user_name) AS display_name
FROM users;
これは、次のCASE式に近い意味を持ちます。
CASE
WHEN nickname IS NOT NULL THEN nickname
ELSE user_name
END
単純にNULLの代替値を指定したいだけなら、CASE式よりCOALESCEの方が読みやすいことが多いです。
NULLIFは特定の値をNULLに変換する
NULLIFは、2つの値が等しい場合にNULLを返します。
SELECT
NULLIF(score, 0) AS score_except_zero
FROM exam_results;
これは、score が0ならNULL、それ以外ならscoreを返す処理です。
CASE式で書くと次のようになります。
CASE
WHEN score = 0 THEN NULL
ELSE score
END
複雑な条件分岐にはCASE式、NULLの補完や単純な置換にはCOALESCEやNULLIFを使うと、SQLが読みやすくなります。
CASE式を使うときの実務上のよくある失敗
CASE式は便利ですが、実務では使い方を誤るとバグや性能問題につながります。
ここでは、現場で起きやすい失敗を整理します。
条件の順番を間違える
最も多い失敗は、条件の順番を間違えることです。
CASE
WHEN amount >= 0 THEN '通常'
WHEN amount >= 100000 THEN '高額'
END
このSQLでは、100,000円以上でも先に amount >= 0 に一致するため、「高額」にはなりません。
範囲判定では、より限定的な条件を先に書きます。
CASE
WHEN amount >= 100000 THEN '高額'
WHEN amount >= 0 THEN '通常'
END
ELSEを書かずにNULLが混入する
ELSEを省略すると、想定外の値がNULLになります。
画面表示なら空欄になり、集計なら件数や合計がずれる原因になります。
特にステータスや区分値は、将来的に新しい値が追加されることがあります。ELSEには「不明」「その他」「未分類」などを明示しておくと安全です。
CASE式に業務ルールを詰め込みすぎる
CASE式が長くなりすぎると、SQLの可読性が大きく下がります。
たとえば、数十個のWHENが並ぶようなSQLは、後から条件を追加・変更するときにミスが起きやすくなります。
次のような場合は、マスタテーブル化を検討します。
・分類ルールが多い
・分類ルールが頻繁に変わる
・複数SQLで同じルールを使う
・業務担当者がルールを管理する
・SQLレビューで条件の妥当性を確認しづらい
CASE式は万能ではありません。短く明確な条件分岐には便利ですが、長期運用するルールはテーブル設計で解決した方がよい場合もあります。
WHERE句のCASEで性能が悪化する
WHERE句にCASE式を入れると、検索条件が複雑になり、インデックスが効きにくくなる場合があります。
特に大量データを扱う場合は、実行計画を確認することが重要です。
性能が問題になる場合は、次のような改善を検討します。
・CASEを使わず条件ごとにSQLを分ける
・必要な条件だけを動的にWHEREへ追加する
・検索用カラムを追加する
・インデックス設計を見直す
・集計結果を事前計算する
SQLは「正しい結果が出る」だけでは不十分です。実務では、データ量が増えても運用できる性能かどうかも確認する必要があります。
DBMSごとのCASE式の違い
CASE式は主要なデータベースで広く利用できますが、細かい挙動や関連構文には違いがあります。
PostgreSQLのCASE式
PostgreSQLでは、CASEは条件式の1つとして扱われます。
公式ドキュメントでは、一般的なCASE構文と、単純CASEに相当する構文が紹介されています。CASEは式として使えるため、SELECT句やORDER BY句などで利用できます。
https://www.postgresql.org/docs/current/functions-conditional.html
MySQLのCASE式
MySQLでは、クエリ内で使うCASE operatorと、ストアドプログラム内で使うCASE statementの違いに注意が必要です。
通常のSELECTやORDER BYで使う場合は、CASE operatorとして次のように書きます。
SELECT
CASE
WHEN score >= 80 THEN 'A'
ELSE 'B'
END AS grade
FROM exam_results;
MySQLの公式ドキュメントでは、CASE operatorは最初に真となった比較または条件の結果を返し、ELSEがない場合はNULLを返すと説明されています。
https://dev.mysql.com/doc/refman/8.0/ja/flow-control-functions.html
SQL ServerのCASE式
SQL Serverでは、CASEはSELECT、UPDATE、DELETE、SET、WHERE、ORDER BY、HAVINGなどで使用できます。
公式ドキュメントでは、単純CASE式は等価比較のみを行い、検索CASE式はBoolean式を順番に評価して最初にTRUEになった結果を返すと説明されています。
https://learn.microsoft.com/ja-jp/sql/t-sql/language-elements/case-transact-sql?view=sql-server-ver17
Oracle DatabaseのCASE式
Oracle Databaseでも、CASE式を使ってSQL文内にIF...THEN...ELSEのようなロジックを書けます。
公式ドキュメントでは、simple CASE expressionとsearched CASE expressionが紹介されています。
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CASE-Expressions.html
CASE式を読みやすく書くためのポイント
CASE式は、ただ動けばよいというものではありません。
チーム開発や長期運用では、後から読んだ人が条件を正しく理解できることが重要です。
条件の粒度をそろえる
CASE式のWHENには、同じ粒度の条件を並べると読みやすくなります。
たとえば、金額ランクの判定なら、すべて金額の条件にそろえます。
CASE
WHEN amount >= 100000 THEN '高額'
WHEN amount >= 50000 THEN '中額'
ELSE '通常'
END
途中にまったく別の条件が混ざると、読み手が意図を追いにくくなります。
条件が重ならないようにする
CASE式では、複数のWHENが同時に真になると、先に書いた条件が優先されます。
そのため、条件はできるだけ排他的に設計します。
CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 AND score < 80 THEN 'B'
ELSE 'C'
END
ただし、この例は次のようにも書けます。
CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 THEN 'B'
ELSE 'C'
END
どちらがよいかはチームの方針によります。明示性を優先するなら前者、簡潔さを優先するなら後者です。
ELSEで想定外ケースを拾う
ELSEは単なるおまけではありません。
想定外の値が来たときに、どのように扱うかを明示する重要な部分です。
CASE
WHEN status = 1 THEN '有効'
WHEN status = 2 THEN '停止中'
ELSE '未定義ステータス'
END
このようにしておくと、データに想定外の値が混ざったときも、画面や帳票で気づきやすくなります。
複雑になったらマスタテーブル化する
CASE式が長くなってきたら、マスタテーブルに切り出せないかを考えます。
たとえば、ステータスコードと表示名を管理するなら、次のようなテーブルを用意できます。
status_master
- status_code
- status_name
- display_order
そして、CASE式ではなくJOINで取得します。
SELECT
a.application_id,
a.title,
sm.status_name
FROM applications a
LEFT JOIN status_master sm
ON a.status = sm.status_code;
この形にすると、表示名や並び順を変更するときにSQLを書き換える必要がなくなります。
CASE式の実務的な使い分け
CASE式は便利ですが、すべての条件分岐をCASEで書くべきではありません。
実務では、次のように使い分けるとよいです。
SQL側でCASE式を書くべき場面
SQL側でCASE式を書くのに向いているのは、データ取得や集計と密接に関係する条件です。
・集計のための分類
・一覧表示の軽いラベル変換
・ORDER BYの表示順制御
・UPDATE時の一括変換
・レポート出力用の条件付き集計
これらは、データベース側で処理した方が一貫性を保ちやすいです。
アプリケーション側に任せた方がよい場面
一方で、次のような条件はアプリケーション側に任せた方がよい場合があります。
・画面ごとに表示ロジックが大きく変わる
・複雑な権限制御が絡む
・外部APIやセッション情報が必要
・頻繁に仕様変更される
・SQLに書くと可読性が大きく落ちる
CASE式は「SQL内で値を変換する道具」です。業務ロジック全体をSQLに押し込むためのものではありません。
CASE式を学ぶとSQLの実務力が上がる理由
CASE式を理解すると、SQLでできることの幅が一気に広がります。
単にデータを取得するだけでなく、取得したデータに意味を与え、業務で使いやすい形に整えられるようになります。
データの意味づけができるようになる
データベースには、数値コードやフラグが多く保存されています。
しかし、利用者にとって重要なのは、status = 1 という値そのものではなく、それが「公開中」なのか「承認済み」なのかという意味です。
CASE式を使えば、SQLの段階でデータに意味を付けられます。
集計SQLの表現力が上がる
CASE式とSUM、COUNTを組み合わせると、条件別の集計が書けるようになります。
これは、管理画面、分析画面、KPIレポート、売上集計などで非常に役立ちます。
SQLで集計条件を表現できるようになると、アプリ側で大量のデータを受け取ってから集計する必要が減り、処理の見通しもよくなります。
SQLレビューで意図を説明しやすくなる
CASE式を適切に書けると、SQLの中に業務ルールを分かりやすく表現できます。
たとえば、次のSQLを見れば、どの条件でどの分類になるのかが明確です。
CASE
WHEN locked_until > CURRENT_TIMESTAMP THEN 'ロック中'
WHEN fail_count > 0 THEN '失敗履歴あり'
ELSE '通常'
END AS login_status
このように、CASE式は仕様確認やレビューにも役立ちます。
まとめ:SQLのCASE式は条件分岐・集計・更新で役立つ実務必須の構文
SQLのCASE式は、プログラミング言語のswitch文やif文に近い感覚で使える条件分岐の構文です。
ただし、CASE式は処理の流れを制御する命令ではなく、条件に応じて1つの値を返す式として理解することが重要です。
CASE式を使うと、次のような処理をSQL内で表現できます。
・ステータスコードを表示名に変換する
・点数や金額をランク分けする
・条件に合うデータだけを集計する
・ORDER BYで任意の表示順に並べる
・UPDATEで条件ごとに値を一括更新する
・NULLや未設定値を分かりやすく扱う
一方で、CASE式を使うときは、次の点に注意が必要です。
・WHENは上から順に評価される
・条件の重複や順番ミスに注意する
・ELSEを省略するとNULLになる
・NULL判定にはIS NULLを使う
・THENやELSEで返す値の型をそろえる
・複雑になりすぎる場合はマスタテーブル化を検討する
CASE式は、SQLの基礎でありながら、実務での応用範囲が非常に広い構文です。SELECT、集計、ORDER BY、UPDATEまで使いこなせるようになると、データ取得だけでなく、業務に合わせたデータ加工やレポート作成まで対応できるようになります。
SQLやデータベースの知識は、Webシステム開発、業務システム開発、データ分析、運用改善など、多くの現場で必要とされます。こうした技術をただ覚えるだけでなく、「実際の業務でどう使うか」まで考えられる方は、開発チームの中でも大きな力になります。
私たちは、SQLやデータベース設計、Webシステム開発に関心を持ち、実務を通じて技術を深めたい方と一緒に働きたいと考えています。知識を現場で活かしながら、より良いシステムづくりに関わっていきたい方は、ぜひ私たちの取り組みや採用情報もご覧ください。
学んだSQLを、実務で使えるスキルにしたい方へ
本記事ではSQLの基本的な考え方や使い方を解説しましたが、
「実務で使えるレベルまで身につけたい」と感じた方も多いのではないでしょうか。
SQLは、文法を理解するだけでなく、
- どんなデータ構造で使われるのか
- どんなクエリが現場で求められるのか
を意識して学ぶことで、実践力が大きく変わります。
そうした「実務を見据えたSQL学習」を進めたい方には、
完全無料で学べるプログラミングスクール ZeroCode PLUS という選択肢もあります。
- SQLを含むWeb・データベース系スキルを体系的に学べる
- 未経験者でも実務を意識したカリキュラム
- 受講料・教材費がかからない完全無料の学習環境
- 完全オンラインでスキマ学習
※学習内容や進め方を確認するだけでもOKです