MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. SQLのCASE式とは?switch相当の条件分岐を実例で解説

SQLのCASE式とは?switch相当の条件分岐を実例で解説

CONTENTS

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
UPDATESET

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 比較対象
  WHEN1 THEN 結果1
  WHEN2 THEN 結果2
  WHEN3 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式では、>=<=ANDORLIKEINIS 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・データベース系スキルを体系的に学べる
  • 未経験者でも実務を意識したカリキュラム
  • 受講料・教材費がかからない完全無料の学習環境
  • 完全オンラインでスキマ学習


ZeroCode PLUSについて詳しく見る

※学習内容や進め方を確認するだけでもOKです

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る