MySQL の CASE 式で条件分岐する
SELECT で取得したデータをそのまま表示するだけでは、実務の要件を満たせない場面があります。たとえば、数値で格納されたステータスを「有効」「無効」のようなラベルに変換したいとき、アプリケーション側で処理するのも一つの手ですが、クエリの段階で変換できればコードがシンプルになります。こうした条件分岐を SQL 上で実現するのが CASE 式です。
CASE 式の基本構文
CASE 式には 2 つの書き方があります。特定のカラムの値を比較する「単純 CASE」と、より柔軟な条件を書ける「検索 CASE」です。
CASE カラム WHEN 値 THEN 結果 のように、1 つのカラムに対して値を列挙する書き方。等価比較しかできない。
CASE WHEN 条件式 THEN 結果 のように、各 WHEN に任意の条件式を書ける。範囲比較や複数カラムの条件も可能。
まずは単純 CASE の例を見てみましょう。users テーブルに status カラムがあり、1 が有効、0 が無効を表しているとします。
SELECT
name,
CASE status
WHEN 1 THEN '有効'
WHEN 0 THEN '無効'
ELSE '不明'
END AS status_label
FROM users;CASE の末尾には必ず END を付けます。AS でエイリアスを指定すると、結果セットのカラム名がわかりやすくなります。ELSE は省略可能ですが、どの WHEN にも一致しない場合に NULL が返るため、明示的に書いておくほうが安全です。
検索 CASE で柔軟な条件を書く
検索 CASE を使うと、等価比較に限らず範囲や複合条件を記述できます。たとえば、商品の価格帯に応じてラベルを付ける場合を考えてみましょう。
SELECT
product_name,
price,
CASE
WHEN price < 1000 THEN 'お手頃'
WHEN price < 5000 THEN '標準'
WHEN price < 10000 THEN 'やや高め'
ELSE '高級'
END AS price_range
FROM products;WHEN は上から順に評価され、最初に一致した条件の THEN が返ります。そのため、条件の順序が重要になります。上の例で price < 5000 が先に来ていますが、すでに price < 1000 を通過しているので、実質的に 1000 以上 5000 未満を意味しています。
この「上から順に評価される」動作は、プログラミングの if-else if チェーンと同じです。一度マッチしたらそれ以降の WHEN は短絡評価されるため、条件が重複していても最初の一致が優先されます。
後続の WHEN を評価せずにスキップする動作のこと。
WHERE 句や ORDER BY での活用
CASE 式は SELECT のカラムリストだけでなく、WHERE 句や ORDER BY 句の中でも使えます。たとえば、特定の条件に応じて並び順を変えたい場合に便利です。
SELECT
name,
role
FROM employees
ORDER BY
CASE role
WHEN 'manager' THEN 1
WHEN 'leader' THEN 2
WHEN 'member' THEN 3
ELSE 4
END;このクエリでは role カラムの値に応じて数値を割り当て、その数値で並び替えています。アルファベット順ではなく業務上の優先度順にソートしたいとき、この手法が役立ちます。
UPDATE と組み合わせる
CASE 式は UPDATE 文の SET 句でも活用できます。一括で条件に応じた値の更新をしたいとき、複数の UPDATE 文を実行する代わりに 1 つのクエリで済ませられます。
UPDATE products
SET discount_rate =
CASE
WHEN stock > 100 THEN 0.3
WHEN stock > 50 THEN 0.2
WHEN stock > 0 THEN 0.1
ELSE 0
END;在庫数に応じて割引率を一括設定する例です。1 回の UPDATE で全行を処理できるため、ループで個別に更新するよりも効率的でしょう。
集計関数との組み合わせ
CASE 式と COUNT や SUM を組み合わせると、1 つのクエリでカテゴリ別の集計ができます。これはクロス集計と呼ばれるテクニックで、実務で非常によく使われるパターンです。
SELECT
department,
COUNT(CASE WHEN status = 'active' THEN 1 END) AS active_count,
COUNT(CASE WHEN status = 'inactive' THEN 1 END) AS inactive_count
FROM employees
GROUP BY department;COUNT は NULL をカウントしないという性質を利用しています。WHEN に一致しなければ ELSE を省略した CASE 式は NULL を返すので、条件に合う行だけがカウントされる仕組みです。
条件に合う行の件数を数える。THEN には 1 など任意の非 NULL 値を指定する。
条件に合う行の値を合計する。THEN に合計したいカラムや式を指定する。
SUM と組み合わせる場合は、THEN に集計したい数値を入れます。
SELECT
department,
SUM(CASE WHEN gender = 'M' THEN salary ELSE 0 END) AS male_salary,
SUM(CASE WHEN gender = 'F' THEN salary ELSE 0 END) AS female_salary
FROM employees
GROUP BY department;このように、CASE 式を使うと 1 つのクエリの中で複数の条件別集計を同時に行えます。部門ごとの男女別給与合計を、テーブルを何度もスキャンすることなく取得できるわけです。
CASE 式を使うときの注意点
CASE 式は便利ですが、使いすぎるとクエリの可読性が下がります。特に、ネストした CASE 式(CASE の中にさらに CASE を入れる書き方)は避けたほうがよいでしょう。条件が複雑になる場合は、ビューや一時テーブルに分割することを検討してください。
条件が単純
CASE 式で対応
条件が複雑化
ビューやサブクエリに分割
また、CASE 式の各 THEN が返すデータ型は統一する必要があります。ある WHEN では文字列、別の WHEN では数値を返すような書き方をすると、暗黙の型変換が発生し、意図しない結果になることがあります。データ型を揃えることは、CASE 式に限らず SQL 全般で意識すべき基本原則です。












