「データを条件に応じて分類したい」
「NULLの代わりにわかりやすい表示をしたい」
「集計結果をカテゴリ別に分けたい」
そんなときに活躍するのが、SQLのCASE文です。
この機能を使えば、ExcelのIF関数のような条件分岐をSQL文の中で実現できます。
この記事では、SQL初心者の方でも理解できるよう、CASE文の基本から実践的な活用方法まで、具体例を交えながらわかりやすく解説します。
CASE文とは

基本的な役割
CASE文は、条件に応じて異なる値を返すためのSQL構文です。
プログラミングのif-else
文やExcelのIF関数
と同じような働きをします。
どんなときに使うの?
データの分類・ラベリング
- 点数を「優・良・可・不可」に分類
- 売上金額を「高額・中額・低額」にカテゴリ分け
- 年齢を「若年層・中年層・高年層」にグループ化
NULL値の置き換え
- データが空の場合に「データなし」と表示
- 未入力項目を「未設定」として表示
条件付き集計
- 特定の条件を満たすデータのみをカウント
- 条件によって異なる計算式を適用
CASE文の基本構文
基本の書き方
SELECT
列名,
CASE
WHEN 条件1 THEN 値1
WHEN 条件2 THEN 値2
WHEN 条件3 THEN 値3
ELSE デフォルト値
END AS 新しい列名
FROM テーブル名;
構文の説明
- CASE:条件分岐の開始を宣言
- WHEN 条件:チェックしたい条件を記述
- THEN 値:条件が真の場合に返す値
- ELSE 値:すべての条件に当てはまらない場合の値(省略可能)
- END:CASE文の終了を宣言
- AS 新しい列名:結果の列に名前を付ける
実行の流れ
- 最初のWHEN条件をチェック
- 条件が真なら対応するTHEN値を返して終了
- 条件が偽なら次のWHEN条件をチェック
- すべての条件が偽ならELSE値を返す
- ELSE句がない場合はNULLを返す
基本的な使用例

例1:成績の評価分類
まず、サンプルデータとして学生の点数表があるとします。
students テーブル
CREATE TABLE students (
name VARCHAR(50),
score INT
);
INSERT INTO students VALUES
('山田太郎', 95),
('田中花子', 82),
('佐藤次郎', 67),
('鈴木三郎', 45),
('高橋四郎', 88);
このデータに対してCASE文を使い、点数に応じた評価を付けてみましょう。
クエリ
SELECT
name AS 名前,
score AS 点数,
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 評価
FROM students
ORDER BY score DESC;
実行結果
名前 | 点数 | 評価 |
---|---|---|
山田太郎 | 95 | S(優秀) |
高橋四郎 | 88 | A(良好) |
田中花子 | 82 | A(良好) |
佐藤次郎 | 67 | C(要努力) |
鈴木三郎 | 45 | D(不合格) |
例2:NULL値の置き換え
データベースにはNULL(空の値)が含まれることがよくあります。CASE文を使ってNULLをわかりやすい表示に変更できます。
employees テーブル
CREATE TABLE employees (
name VARCHAR(50),
department VARCHAR(50),
phone VARCHAR(20)
);
INSERT INTO employees VALUES
('田中一郎', '営業部', '090-1234-5678'),
('山田二郎', '開発部', NULL),
('佐藤三郎', NULL, '090-9876-5432'),
('鈴木四郎', '総務部', '090-5555-1111');
クエリ
SELECT
name AS 名前,
CASE
WHEN department IS NULL THEN '部署未設定'
ELSE department
END AS 部署,
CASE
WHEN phone IS NULL THEN '電話番号未登録'
ELSE phone
END AS 電話番号
FROM employees;
実行結果
名前 | 部署 | 電話番号 |
---|---|---|
田中一郎 | 営業部 | 090-1234-5678 |
山田二郎 | 開発部 | 電話番号未登録 |
佐藤三郎 | 部署未設定 | 090-9876-5432 |
鈴木四郎 | 総務部 | 090-5555-1111 |
集計関数との組み合わせ

CASE文の真価は、集計関数と組み合わせたときに発揮されます。条件付きでのカウントや合計計算が可能になります。
例3:条件付きカウント
売上データから、金額帯別の取引件数を集計してみましょう。
sales テーブル
CREATE TABLE sales (
product_name VARCHAR(50),
category VARCHAR(30),
amount INT,
sale_date DATE
);
INSERT INTO sales VALUES
('ノートPC', '電子機器', 120000, '2025-01-15'),
('マウス', '電子機器', 2500, '2025-01-16'),
('デスク', '家具', 45000, '2025-01-17'),
('椅子', '家具', 25000, '2025-01-18'),
('キーボード', '電子機器', 8000, '2025-01-19'),
('テーブル', '家具', 80000, '2025-01-20');
クエリ
SELECT
category AS カテゴリ,
COUNT(*) AS 総取引数,
COUNT(CASE WHEN amount >= 50000 THEN 1 END) AS 高額取引数,
COUNT(CASE WHEN amount >= 10000 AND amount < 50000 THEN 1 END) AS 中額取引数,
COUNT(CASE WHEN amount < 10000 THEN 1 END) AS 低額取引数
FROM sales
GROUP BY category
ORDER BY category;
実行結果
カテゴリ | 総取引数 | 高額取引数 | 中額取引数 | 低額取引数 |
---|---|---|---|---|
家具 | 3 | 1 | 2 | 0 |
電子機器 | 3 | 1 | 1 | 1 |
例4:条件付き合計
同じデータを使って、条件別の売上合計を計算してみましょう。
クエリ
SELECT
category AS カテゴリ,
SUM(amount) AS 総売上金額,
SUM(CASE WHEN amount >= 50000 THEN amount ELSE 0 END) AS 高額商品売上,
SUM(CASE WHEN amount < 50000 THEN amount ELSE 0 END) AS 中低額商品売上,
ROUND(
AVG(CASE WHEN amount >= 50000 THEN amount END), 0
) AS 高額商品平均単価
FROM sales
GROUP BY category
ORDER BY 総売上金額 DESC;
実行結果
カテゴリ | 総売上金額 | 高額商品売上 | 中低額商品売上 | 高額商品平均単価 |
---|---|---|---|---|
家具 | 150000 | 80000 | 70000 | 80000 |
電子機器 | 130500 | 120000 | 10500 | 120000 |
応用的な使い方
CASE文のネスト(入れ子)
複雑な条件分岐が必要な場合は、CASE文を入れ子にできます。
例5:年齢と性別による分類
-- 従業員の年齢と性別による詳細分類
SELECT
name AS 名前,
age AS 年齢,
gender AS 性別,
CASE
WHEN age < 30 THEN
CASE
WHEN gender = '男性' THEN '若手男性社員'
WHEN gender = '女性' THEN '若手女性社員'
ELSE '若手社員'
END
WHEN age >= 30 AND age < 50 THEN
CASE
WHEN gender = '男性' THEN '中堅男性社員'
WHEN gender = '女性' THEN '中堅女性社員'
ELSE '中堅社員'
END
ELSE
CASE
WHEN gender = '男性' THEN 'ベテラン男性社員'
WHEN gender = '女性' THEN 'ベテラン女性社員'
ELSE 'ベテラン社員'
END
END AS 社員分類
FROM employee_details;
注意点 ネストが深くなると読みにくくなるため、以下のような工夫をおすすめします:
- 適度に改行やインデントを使用
- 複雑すぎる場合はビューやサブクエリに分割
- コメントを追加して意図を明確にする
複数条件の組み合わせ
複数の列を同時に判定する場合の書き方です。
例6:売上と利益率による商品評価
SELECT
product_name AS 商品名,
sales_amount AS 売上金額,
profit_rate AS 利益率,
CASE
WHEN sales_amount >= 100000 AND profit_rate >= 0.3 THEN 'スター商品'
WHEN sales_amount >= 100000 AND profit_rate >= 0.2 THEN '優良商品'
WHEN sales_amount >= 50000 AND profit_rate >= 0.2 THEN '標準商品'
WHEN sales_amount < 50000 AND profit_rate >= 0.4 THEN 'ニッチ商品'
WHEN profit_rate < 0.1 THEN '要改善商品'
ELSE '一般商品'
END AS 商品評価
FROM products
ORDER BY sales_amount DESC, profit_rate DESC;
CASE文使用時の注意点
データ型の統一
CASE文の各THEN句で返す値は、可能な限り同じデータ型にしましょう。
良い例
CASE
WHEN score >= 80 THEN '合格'
WHEN score >= 60 THEN '要再試験'
ELSE '不合格'
END
-- すべて文字列型で統一
避けるべき例
CASE
WHEN score >= 80 THEN '合格'
WHEN score >= 60 THEN 60 -- 数値型
ELSE '不合格'
END
-- 文字列型と数値型が混在(予期しない結果の原因)
ELSE句の重要性
ELSE句を省略すると、どの条件にも当てはまらない場合にNULLが返されます。
-- ELSE句なしの場合
SELECT
name,
CASE
WHEN score >= 80 THEN '合格'
WHEN score >= 60 THEN '要再試験'
-- 60未満の場合、NULLが返される
END AS 結果
FROM students;
-- ELSE句ありの場合(推奨)
SELECT
name,
CASE
WHEN score >= 80 THEN '合格'
WHEN score >= 60 THEN '要再試験'
ELSE '不合格' -- 明示的に値を指定
END AS 結果
FROM students;
パフォーマンスへの配慮
大量のデータを扱う場合は、条件の順序を工夫することでパフォーマンスを向上できます。
-- より頻繁に該当する条件を上に配置
CASE
WHEN status = 'active' THEN '稼働中' -- 最も多い状態
WHEN status = 'inactive' THEN '停止中' -- 次に多い状態
WHEN status = 'maintenance' THEN '保守中' -- 少ない状態
ELSE '不明'
END
実践的な活用パターン

パターン1:データクレンジング
データベースの中には、表記ゆれや不統一なデータが含まれることがあります。CASE文を使って統一できます。
-- 都道府県名の表記統一
SELECT
customer_name,
CASE
WHEN prefecture IN ('東京', '東京都', 'Tokyo') THEN '東京都'
WHEN prefecture IN ('大阪', '大阪府', 'Osaka') THEN '大阪府'
WHEN prefecture IN ('神奈川', '神奈川県', 'Kanagawa') THEN '神奈川県'
ELSE prefecture
END AS 統一都道府県名
FROM customers;
パターン2:ビジネスロジックの実装
複雑な料金計算や手数料計算をCASE文で実装できます。
-- 購入金額に応じた配送料計算
SELECT
order_id,
total_amount,
CASE
WHEN total_amount >= 10000 THEN 0 -- 1万円以上で送料無料
WHEN total_amount >= 5000 THEN 300 -- 5千円以上で300円
WHEN total_amount >= 3000 THEN 500 -- 3千円以上で500円
ELSE 800 -- それ以外は800円
END AS 配送料,
total_amount +
CASE
WHEN total_amount >= 10000 THEN 0
WHEN total_amount >= 5000 THEN 300
WHEN total_amount >= 3000 THEN 500
ELSE 800
END AS 請求総額
FROM orders;
パターン3:レポート作成
月次・年次レポートでのカテゴリ分類に活用できます。
-- 月別売上サマリー
SELECT
EXTRACT(MONTH FROM sale_date) AS 月,
COUNT(*) AS 総取引数,
SUM(amount) AS 総売上金額,
COUNT(CASE WHEN amount >= 100000 THEN 1 END) AS 大口取引数,
CASE
WHEN SUM(amount) >= 5000000 THEN '目標達成'
WHEN SUM(amount) >= 4000000 THEN '目標まであと少し'
ELSE '目標未達'
END AS 達成状況
FROM sales
WHERE EXTRACT(YEAR FROM sale_date) = 2025
GROUP BY EXTRACT(MONTH FROM sale_date)
ORDER BY 月;
他のSQL機能との組み合わせ
WHERE句との連携
CASE文の結果を条件として使用できます。
-- 評価が「要改善」の商品のみを抽出
SELECT *
FROM (
SELECT
product_name,
sales_amount,
profit_rate,
CASE
WHEN sales_amount < 50000 AND profit_rate < 0.1 THEN '要改善'
WHEN sales_amount >= 100000 AND profit_rate >= 0.3 THEN 'スター商品'
ELSE '一般商品'
END AS 評価
FROM products
) AS evaluated_products
WHERE 評価 = '要改善';
ORDER BY句での活用
独自の並び順を実現できます。
-- 優先度に応じたカスタムソート
SELECT
task_name,
priority,
due_date
FROM tasks
ORDER BY
CASE priority
WHEN '緊急' THEN 1
WHEN '高' THEN 2
WHEN '中' THEN 3
WHEN '低' THEN 4
ELSE 5
END,
due_date;
まとめ
SQLのCASE文は、データの分類、NULL値の処理、条件付き集計など、様々な場面で活用できる強力な機能です。
この記事のポイント
基本構文の理解
- CASE – WHEN – THEN – ELSE – END の流れ
- 条件は上から順番にチェックされる
- ELSE句で予期しない値への対応
実践的な活用方法
- データの分類とラベリング
- NULL値の置き換え
- 集計関数との組み合わせによる条件付き計算
- 複雑なビジネスロジックの実装
注意すべきポイント
- データ型の統一
- ELSE句の明示的な指定
- パフォーマンスを考慮した条件順序
- 可読性を保つためのネストの制限
コメント