サイトアイコン ITC Media

【完全版】SQLのCASE文とは?基本から応用まで実例付きで解説

(最終更新月:2023年5月)

✔このような方へ向けて書かれた記事となります

「SQL言語で条件分岐がしたい」

「CASEの使い方がわからない」

「CASEで何ができるのだろうか」

✔当記事を通じてお伝えすること

当記事では、SQL言語のCASEについて、基本的な書き方はもちろん、応用した使い方まで丁寧に解説していきます。

ぜひ最後までご覧ください。

✔当記事の信頼性

当記事では、Python言語をベースとしたDjangoフレームワークで、アプリの公開方法をご紹介しています。

データの保存場所は、サーバー内で動くpostgreSQL(ポスグレ)です。

Djangoを使えばSQLをマスターしておく必要はないものの、最低限の知識として、かなり勉強しました。

実際のコードや写真付きで、できる限り丁寧に解説します。

※Djangoのチュートリアルはこちら。

created by Rinker
¥2,838 (2025/01/18 09:24:43時点 楽天市場調べ-詳細)
SQL学習におすすめ

筆者プロフィール

【現職】プロダクトマネージャー

【副業】ブログ(月間20万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。現在はプロダクトマネージャーとして、さまざまな関係者の間に入り奮闘してます。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系Webアプリ

✔人に見せても恥ずかしくないコードを書こう

「リーダブルコード」は、わかりやすく良いコードの定義を教えてくれる本です。

  • 見るからにきれいなコードの書き方
  • コードの分割方法
  • 変数や関数の命名規則

エンジニアのスタンダートとすべき基準を一から解説しています。

何回も読むのに値する本なので、ぜひ手にとって読んでみてください。

【SQL】CASEで知っておくべき基礎事項

CASEを学ぶための必須事項を見ていきます。

応用した使い方まで知るためにも、必ず目を通しておきましょう。

SQLとは

SQL(Structured Query Language)は、リレーショナルデータベース管理システム(RDBMS)でデータ操作や定義、制御を行うための標準的な言語です。

データベースに対する以下のような操作ができる言語になります。

CASE文の概要

CASE文は、SQLクエリ内で条件分岐を実現する強力なツールです。

それは複数の条件を評価し、各条件に対応する結果を返します。

以下の例では、顧客の年齢に基づいて年齢グループを割り当てます。

SELECT customer_id, age,
       CASE
  WHEN age < 20 THEN 'Teen'
  WHEN age BETWEEN 20 AND 64 THEN 'Adult'
  WHEN age >= 65 THEN 'Senior'
  ELSE 'Unknown'
       END as age_group
FROM customers;

この例では、CASE文が3つの異なる条件を評価して、それぞれに対応する結果を返しています。

顧客の年齢対応する結果
20歳未満‘Teen’
20歳から64歳‘Adult’
65歳以上‘Senior’

どの条件も満たされない場合、ELSE句が使われ、’Unknown’が返されます。

CASE文とIF文の違い

CASE文とIF文は両方とも条件に基づいた結果を返すための制御フロー構造ですが、その使い方と適用範囲にはいくつかの重要な違いがあります。

  1. CASEでは複数の条件で結果を返せる
  2. IF文は、サポートされていないシステムもある

CASEでは複数の条件で結果を返せる

CASE文は複数の条件を照らし合わせて結果を返すのに対し、IF文は単一の条件を評価して結果を返します。

以下にMySQLのIF文の例を示します。

SELECT customer_id, age,
       IF(age < 20, 'Teen', 'Non-teen') as age_group
FROM customers;

このクエリは、もし顧客の年齢が20歳未満ならば’Teen’を返し、そうでなければ’Non-teen’を返します。

複数の条件を評価するためには、複数のIF文をネストする必要があります。

IF文は、サポートされていないシステムもある

CASE文はSQL標準であり、ほとんどのリレーショナルデータベース管理システム(RDBMS)でサポートされています。

一方、IF文はデータベースによります。

例えばPostgreSQLでは、条件式にCASE文が推奨されています。

条件式

これらの違いを理解することで、特定の状況やデータベースシステムに最適な選択を行うことができます

CASE文の基本構文

CASE文の基本構文をご覧ください。

文法として、どのような順番で書くかをおさえましょう。

 単純CASE式

単純CASE式は、ある列の値に応じて結果を返すものです。

SELECT 列1, 列2,

       CASE 列3

   WHEN 条件1(値1) THEN 出力結果1

   WHEN 条件2(値2) THEN 出力結果2

   WHEN 条件3(値3) THEN 出力結果3

   ELSE 出力結果4(上の条件に満たないときの出力結果4)

      END as 結果セットの列名

FROM データを操作するテーブル名;

以下に例を示します。

SELECT customer_id, total_purchase,
       CASE membership_level
WHEN 'Bronze' THEN 'Low'
WHEN 'Silver' THEN 'Medium'
WHEN 'Gold' THEN 'High'
ELSE 'Unknown'
       END as membership_category
FROM customers;

試してみたい方はこちらでテーブルを作って試してみよう。

SQL Fiddle - Online SQL Compiler for learning & practice
Discover our free online SQL editor enhanced with AI to chat, explain, and generate code. Support SQL Server, MySQL, Mar...
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    total_purchase DECIMAL(10,2),
    membership_level VARCHAR(10)
);

INSERT INTO customers (customer_id, total_purchase, membership_level)
VALUES (1, 100.00, 'Bronze'),
       (2, 200.00, 'Silver'),
       (3, 300.00, 'Gold'),
       (4, 400.00, 'Bronze'),
       (5, 500.00, 'Platinum');

出力結果

customer_idtotal_purchasemembership_category
1100Low
2200Medium
3300High
4400Low
5500Unknown

検索CASE式

検索CASE式は、複数の条件を評価して結果を返します。

以下がその例です。

SELECT customer_id, age,
       CASE
WHEN age < 20 THEN 'Teenager'
WHEN age BETWEEN 20 AND 64 THEN 'Adult'
WHEN age >= 65 THEN 'Senior'
ELSE 'Unknown'
       END as age_group
FROM customers;

CASE文の注意点

CASE文で覚えておくべき注意点は以下のとおりです。

CASE文とNULLの取り扱い

CASE文でNULL値を扱う場合は、IS NULLまたはIS NOT NULL演算子を使用します。

以下に例を示します。

SELECT product_id, price,
       CASE
WHEN price IS NULL THEN 'Not available'
ELSE
'Available'
       END as availability
FROM products;

実践的な例で学ぶCASE文

実践ではどのように使われているのかをご紹介します。

具体例を見て、使いたいケースに近いものを探しましょう。

成績の評価を行う例

以下の例では、学生の得点に基づいて成績を評価しています。

CASE文例

SELECT student_id, score,
       CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
WHEN score >= 60 THEN 'D'
ELSE 'F'
       END as grade
FROM students;

テーブル作成のSQL

こちらでテーブルを作り試してみました。

SQL Fiddle - Online SQL Compiler for learning & practice
Discover our free online SQL editor enhanced with AI to chat, explain, and generate code. Support SQL Server, MySQL, Mar...
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    score INT
);

INSERT INTO students (student_id, score)
VALUES (1, 95),
       (2, 85),
       (3, 75),
       (4, 65),
       (5, 55);

出力結果

student_idscoregrade
195A
285B
375C
465D
555F

カテゴリ別の売上集計を行う例

以下の例では、商品カテゴリごとに売上を集計しています。

CASE文例

SELECT category,
       SUM(CASE WHEN month = 'Jan' THEN sales ELSE 0 END) as Jan_sales,
       SUM(CASE WHEN month = 'Feb' THEN sales ELSE 0 END) as Feb_sales,
       SUM(CASE WHEN month = 'Mar' THEN sales ELSE 0 END) as Mar_sales,
       SUM(CASE WHEN month = 'Apr' THEN sales ELSE 0 END) as Apr_sales
FROM sales_data
GROUP BY category;

テーブル作成のSQL

テーブルはこちらで作りましょう。

CREATE TABLE sales_data (
    category VARCHAR(20),
    month VARCHAR(3),
    sales DECIMAL(10,2)
);

INSERT INTO sales_data (category, month, sales)
VALUES ('Electronics', 'Jan', 1000.00),
       ('Electronics', 'Feb', 1500.00),
       ('Electronics', 'Mar', 1200.00),
       ('Electronics', 'Apr', 1300.00),
       ('Furniture', 'Jan', 900.00),
       ('Furniture', 'Feb', 700.00),
       ('Furniture', 'Mar', 800.00),
       ('Furniture', 'Apr', 1000.00);

出力結果

categoryJan_salesFeb_salesMar_salesApr_sales
Electronics1000150012001300
Furniture9007008001000

データの欠損値を補完する例

以下の例では、価格がNULLの場合に平均価格で補完しています。

文例

SELECT product_id,
       COALESCE(price, (SELECT AVG(price) FROM products WHERE price IS NOT NULL)) as adjusted_price
FROM products;

テーブル作成のSQL

CREATE TABLE products (
    product_id INT PRIMARY KEY,
    price DECIMAL(10,2)
);

INSERT INTO products (product_id, price)
VALUES (1, 100.00),
       (2, 200.00),
       (3, NULL),
       (4, 400.00),
       (5, NULL);

出力結果

product_idadjusted_price
1100
2200
3233.333333
4400
5233.333333

CASE文を使った応用例

CASE文を使った応用例も見ていきましょう。

CASEを使うだけでなく、ほかの処理とも組み合わせていきます。

CASE文を使ったソート

以下の例では、CASE文を使って特定の条件でソートしています。

SELECT customer_id, total_purchase, membership_level
FROM customers
ORDER BY CASE membership_level
  WHN 'Gold' THEN 1
  WHEN 'Silver' THEN 2
  WHEN 'Bronze' THEN 3
  ELSE 4
END;

CASE文を使った集計

以下の例では、性別と年齢層ごとの顧客数を集計しています。

SELECT gender,
       COUNT(CASE
      WHEN age < 20 THEN 1
      ELSE NULL
    END) as teenagers,
       COUNT(CASE
      WHEN age BETWEEN 20 AND 64 THEN 1
      ELSE NULL
    END) as adults,
       COUNT(CASE
      WHEN age >= 65 THEN 1
      ELSE NULL
    END) as seniors
FROM customers
GROUP BY gender;

CASE文を使ったデータの更新

以下の例では、在庫が一定数以下の場合に注文ステータスを更新しています。

UPDATE orders
SET order_status = CASE
   WHEN stock <= 10 THEN 'Low Stock'
   ELSE 'In Stock'
 END;

CASE文を使った条件付き結合

以下の例では、CASE文を使って顧客の会員レベルに応じて異なるディスカウントテーブルと結合しています。

SELECT c.customer_id, c.membership_level, p.product_id, p.price,
       p.price * d.discount_rate as discounted_price
FROM customers c
JOIN products p
JOIN discounts d ON d.discount_id =
  CASE c.membership_level
    WHEN 'Gold' THEN p.gold_discount_id
    WHEN 'Silver' THEN p.silver_discount_id
    WHEN 'Bronze' THEN p.bronze_discount_id
    ELSE p.default_discount_id
  END;

CASE文のパフォーマンスに関する注意点

CASE文を扱うにあたって、気を付けるべき点とその対処法を見ていきます。

うまくいかないときのために、事前に調べておきましょう。

結果の選択肢が多い場合の対処法

CASE文を使って複数の選択肢を評価すると、特に選択肢の数が多い場合、パフォーマンスが低下する可能性があります。

解決策としては、サブクエリやテーブル結合を使用して問題を回避する方法が挙げられます。

例えば、次のようなCASE文があるとします。

SELECT product_id,
       CASE product_id
         WHEN 1 THEN 'Product 1'
         WHEN 2 THEN 'Product 2'
         -- ... hundreds or thousands more options ...
         WHEN 10000 THEN 'Product 10000'
         ELSE 'Unknown Product'
       END as product_name
FROM products;

これは、商品IDが1から10,000までの各商品に対応する商品名を取得しようとしています。

しかし、選択肢が多いため、このクエリは効率的ではありません。

代わりに、別のテーブル(たとえば`product_names`)を作成し、商品IDと商品名をマッピングすることができます。

CREATE TABLE product_names (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100)
);

そして、このテーブルを元の`products`テーブルと結合することで、同じ結果を得られるのです。

SELECT p.product_id,
       COALESCE(n.product_name, 'Unknown Product') as product_name
FROM products p
LEFT JOIN product_names n ON p.product_id = n.product_id;

このクエリでは、商品IDに対応する商品名が`product_names`テーブルに存在しない場合、’Unknown Product’が使用されます。

これにより、CASE文を使用するよりも効率的に商品名を取得できます。

インデックスの活用

CASE文が検索条件に含まれる場合、インデックスの利用が制限されることがあります。

インデックスを効果的に活用するために、検索条件を工夫するか、CASE文を使わない方法を検討してください。

最適化ヒントの活用

データベースによっては、最適化ヒントを使用してクエリプランを調整することができます。パフォーマンス問題が発生した場合、最適化ヒントの活用を検討してください。

無料SQLツール:SQL Fiddle

当記事で共有している写真も、SQL Fiddleを使ってご説明しました。

特徴は以下のとおり。

以下のように、左側でテーブルやカラムの設定をおこない、右側でコードが実行できるのです。

SQL言語を学ぶなら、登録してくことをおすすめします!

ちなみに今回のデータベース設定として、SQL Fiddleの左側に書いたコードはこちら。

CREATE TABLE players_2022(
  id SERIAL primary key,
  name varchar(50),
  score integer
);

CREATE TABLE players_all_time(
  id SERIAL primary key,
  name varchar(50),
  score integer
);

INSERT INTO players_2022 (name, score) VALUES ('エンバペ', 8);
INSERT INTO players_2022 (name, score) VALUES ('メッシ', 7);
INSERT INTO players_2022 (name, score) VALUES ('ジルー', 4);
INSERT INTO players_2022 (name, score) VALUES ('アルバレス', 4);
INSERT INTO players_2022 (name, score) VALUES ('バレンシア', 3);
INSERT INTO players_2022 (name, score) VALUES ('ガクポ', 3);
INSERT INTO players_2022 (name, score) VALUES ('西藤', 1);

INSERT INTO players_all_time (name, score) VALUES ('クローゼ', 16);
INSERT INTO players_all_time (name, score) VALUES ('ロナウド', 15);
INSERT INTO players_all_time (name, score) VALUES ('ミュラー', 14);
INSERT INTO players_all_time (name, score) VALUES ('フォンテーヌ', 13);
INSERT INTO players_all_time (name, score) VALUES ('西藤', 3);

コピーして活用してください。

まとめ

当記事でお伝えしてきたことはこちら。

CASE文により、条件に応じて値を返す柔軟なクエリを作成できます。

今回学んだ知識を活かして、実際のデータベースでCASE文を使ったクエリを作成してみてください。

また、他のSQL機能やデータベース管理に関する知識も学び、スキルをさらに磨いていきましょう。

モバイルバージョンを終了