SQLのCASE式の使い方:単純CASEと検索CASEを実例で解説

black laptop computer turned-on displaying source code on table SQL

SQLで「値によって表示を変えたい」「条件に応じて計算式を切り替えたい」という場面は、実務でも頻繁に登場します。そのような条件分岐を実現するのがCASE式です。プログラミング言語のif文に相当するCASE式には、値の等値比較に特化した「単純CASE」と、任意の条件を書ける「検索CASE」の2種類があります。本記事では両者の構文の違いと使い分け、SELECT・ORDER BY・GROUP BY内での活用例、そしてNULLを扱う際の注意点を、実際のSQLを交えて解説します。

このシナリオで考える

今回は売上管理システムを例にします。商品の注文を管理する orders テーブルを使います。status 列には 'pending'(処理中)・'shipped'(発送済み)・'cancelled'(キャンセル)の3種類の値が入ります。

CREATE TABLE orders (
  id         INT           NOT NULL AUTO_INCREMENT PRIMARY KEY,
  user_id    INT           NOT NULL,
  product    VARCHAR(50)   NOT NULL,
  category   VARCHAR(20)   NOT NULL,
  amount     DECIMAL(10,2) NOT NULL,
  status     VARCHAR(20)   NOT NULL,
  created_at DATE          NOT NULL
);

INSERT INTO orders (user_id, product, category, amount, status, created_at) VALUES
(1, 'ノートPC',   'electronics', 120000, 'shipped',   '2026-05-01'),
(2, 'マウス',     'electronics',   3500, 'shipped',   '2026-05-02'),
(3, 'Tシャツ',    'apparel',       2800, 'pending',   '2026-05-03'),
(4, 'デスク',     'furniture',    45000, 'cancelled', '2026-05-04'),
(5, 'キーボード', 'electronics',   8000, 'shipped',   '2026-05-05'),
(6, 'ジャケット', 'apparel',      12000, 'pending',   '2026-05-06');

単純CASEの書き方

単純CASE(Simple CASE)は、1つの値を複数の選択肢と等値比較します。構文は以下の通りです。

CASE <比較対象>
  WHEN <値1> THEN <結果1>
  WHEN <値2> THEN <結果2>
  ...
  [ELSE <それ以外の結果>]
END

status 列の英語値を日本語に変換してみましょう。

SELECT
  product,
  amount,
  CASE status
    WHEN 'shipped'   THEN '発送済み'
    WHEN 'pending'   THEN '処理中'
    WHEN 'cancelled' THEN 'キャンセル'
    ELSE '不明'
  END AS status_ja
FROM orders;
product amount status_ja
ノートPC 120000.00 発送済み
マウス 3500.00 発送済み
Tシャツ 2800.00 処理中
デスク 45000.00 キャンセル
キーボード 8000.00 発送済み
ジャケット 12000.00 処理中

単純CASEは「1つの列を複数の固定値と照合する」場面に向いています。ELSE を書いておくと、どの WHEN にも一致しなかった場合の結果を明示できます。ELSE を省略すると NULL が返るため、意図しない NULL を防ぐために書いておくのが安全です。

検索CASEの書き方

検索CASE(Searched CASE)は比較対象を固定せず、WHEN 節に任意の条件式を書けます。

CASE
  WHEN <条件1> THEN <結果1>
  WHEN <条件2> THEN <結果2>
  ...
  [ELSE <それ以外の結果>]
END

amount の金額に応じてランクを付けてみましょう。

SELECT
  product,
  amount,
  CASE
    WHEN amount >= 100000 THEN 'S'
    WHEN amount >=  10000 THEN 'A'
    WHEN amount >=   5000 THEN 'B'
    ELSE                       'C'
  END AS rank
FROM orders;
product amount rank
ノートPC 120000.00 S
マウス 3500.00 C
Tシャツ 2800.00 C
デスク 45000.00 A
キーボード 8000.00 B
ジャケット 12000.00 A

WHEN の条件は上から順に評価され、最初に真になった節の結果が返ります。範囲比較・複合条件(AND/OR)・サブクエリも書けるため、単純CASEより表現力が高いです。

単純CASEと検索CASEの使い分け

2種類のCASEをまとめると以下のようになります。

単純CASE 検索CASE
比較方法 等値比較(=)固定 任意の条件式
NULLの比較 不可(常に不一致) IS NULLで可能
範囲比較 不可 可能(>=、BETWEENなど)
複合条件 不可 AND/ORで可能
可読性 同じ列の比較には高い 複雑な条件にも対応

迷ったときは検索CASEを選べば間違いありません。単純CASEは「同じ列の値を複数の固定値と比較する」場面に限定すると、コードが読みやすくなります。

CASE式を使える場所

ORDER BYでカスタム並び順を作る

文字列の辞書順とは異なる業務上の順序で並べ替えたいとき、CASE式が役立ちます。status を「処理中 → 発送済み → キャンセル」の優先順で並べる例です。

SELECT product, status
FROM orders
ORDER BY
  CASE status
    WHEN 'pending'   THEN 1
    WHEN 'shipped'   THEN 2
    WHEN 'cancelled' THEN 3
    ELSE 99
  END;

インデックスや追加カラムなしに、任意のカスタム順を実現できます。

GROUP BYで集計軸を動的に変える

category をおおまかに「デジタル」と「その他」にまとめて集計してみましょう。

SELECT
  CASE category
    WHEN 'electronics' THEN 'デジタル'
    ELSE 'その他'
  END          AS category_group,
  SUM(amount)  AS total_amount,
  COUNT(*)     AS order_count
FROM orders
GROUP BY
  CASE category
    WHEN 'electronics' THEN 'デジタル'
    ELSE 'その他'
  END;
category_group total_amount order_count
デジタル 131500.00 3
その他 59800.00 3

GROUP BY にエイリアス(category_group)を書くとMySQLのバージョンによってはエラーになることがあります。CASE式をそのまま繰り返すか、サブクエリで包む方が確実です。

よくある落とし穴

単純CASEでNULLを比較しようとする

単純CASEの WHEN は内部で等値演算子(=)を使います。NULL = NULL の結果は TRUE でも FALSE でもなく UNKNOWN になるため、WHEN NULL は決して一致しません。

-- NG: status が NULL でも 'データなし' にならない
CASE status
  WHEN NULL      THEN 'データなし'  -- 永遠にマッチしない
  WHEN 'shipped' THEN '発送済み'
  ELSE 'その他'
END

NULLを判定するには検索CASEと IS NULL を組み合わせます。

-- OK: IS NULL で正しく検出できる
CASE
  WHEN status IS NULL    THEN 'データなし'
  WHEN status = 'shipped' THEN '発送済み'
  ELSE 'その他'
END

ELSEを省略してNULLが混入する

どの WHEN にも一致しなかった場合、ELSE がなければ NULL が返ります。この NULL が SUM や文字列連結に流れ込むと、予期しない結果になります。数値を期待する場所では ELSE 0、文字列なら ELSE '' を明示するのが安全な習慣です。

-- キャンセル分を除外して合計する例
SELECT SUM(
  CASE
    WHEN status = 'cancelled' THEN 0
    ELSE amount
  END
) AS effective_total
FROM orders;

THEN節の型を混在させる

1つのCASE式の中でTHEN節の型が混在すると、MySQLは暗黙の型変換を行います。数値と文字列が混在すると全体が文字列として扱われることがあります。型を統一するか、CAST() で明示的に変換することをお勧めします。

-- 意図しない型変換の例
CASE status
  WHEN 'shipped' THEN 100    -- 数値
  ELSE '未確定'              -- 文字列 → 全体が文字列になる可能性
END

-- 型を統一した例
CASE status
  WHEN 'shipped' THEN CAST(100 AS CHAR)
  ELSE '未確定'
END

まとめ

CASE式には「単純CASE(等値比較)」と「検索CASE(任意条件)」の2種類があります。SELECT列・ORDER BY・GROUP BYなど式が書ける場所であれば使えます。NULLの比較には IS NULL を用いる検索CASEが必要で、ELSE の省略は意図しないNULLの原因になります。この3点を押さえておけば、CASE式を安全に活用できます。

参考リンク

アイキャッチ画像: Photo by Jantine Doornbos on Unsplash

タイトルとURLをコピーしました