(最終更新月:2023年5月)
✔このような方へ向けて書かれた記事となります
「SQL言語で条件分岐がしたい」
「CASEの使い方がわからない」
「CASEで何ができるのだろうか」
✔当記事を通じてお伝えすること
- CASEとは
- CASEの書き方
- CASEでできること
当記事では、SQL言語のCASEについて、基本的な書き方はもちろん、応用した使い方まで丁寧に解説していきます。
ぜひ最後までご覧ください。
✔当記事の信頼性
当記事では、Python言語をベースとしたDjangoフレームワークで、アプリの公開方法をご紹介しています。
データの保存場所は、サーバー内で動くpostgreSQL(ポスグレ)です。
Djangoを使えばSQLをマスターしておく必要はないものの、最低限の知識として、かなり勉強しました。
実際のコードや写真付きで、できる限り丁寧に解説します。
※Djangoのチュートリアルはこちら。
【SQL】CASEで知っておくべき基礎事項
CASEを学ぶための必須事項を見ていきます。
応用した使い方まで知るためにも、必ず目を通しておきましょう。
- SQLとは
- CASE文の概要
- CASE文とIF文の違い
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文は両方とも条件に基づいた結果を返すための制御フロー構造ですが、その使い方と適用範囲にはいくつかの重要な違いがあります。
- CASEでは複数の条件で結果を返せる
- 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式
- CASE文の注意点
- CASE文とNULLの取り扱い
単純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;
試してみたい方はこちらでテーブルを作って試してみよう。
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_id | total_purchase | membership_category |
---|---|---|
1 | 100 | Low |
2 | 200 | Medium |
3 | 300 | High |
4 | 400 | Low |
5 | 500 | Unknown |
検索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文で覚えておくべき注意点は以下のとおりです。
- 必ずENDキーワードを使用する: ENDがないと、SQLはCASE文がどこで終了するのかを知らないため、エラーが発生
- ELSE句の使用: CASE文の中にある条件のいずれも満たされない場合、SQLは何をすべきかを知らないため、意図しない結果を返す可能性がある
- ネストしたCASE文の扱い: CASE文は他のCASE文の中にネストできるが、適切なインデントとカッコを使用して可読性を保つようにする
- 順序の重要性: CASE文は上から順に評価され、最初に真となる条件が結果を決定するため、順番に気を付ける
- NULL値の取り扱い: CASE文では、評価される式がNULLの場合、その条件は偽と評価される
- パフォーマンスへの影響: 特に大きなテーブルで複雑な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
こちらでテーブルを作り試してみました。
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_id | score | grade |
---|---|---|
1 | 95 | A |
2 | 85 | B |
3 | 75 | C |
4 | 65 | D |
5 | 55 | F |
カテゴリ別の売上集計を行う例
以下の例では、商品カテゴリごとに売上を集計しています。
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);
出力結果
category | Jan_sales | Feb_sales | Mar_sales | Apr_sales |
---|---|---|---|---|
Electronics | 1000 | 1500 | 1200 | 1300 |
Furniture | 900 | 700 | 800 | 1000 |
データの欠損値を補完する例
以下の例では、価格が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_id | adjusted_price |
---|---|
1 | 100 |
2 | 200 |
3 | 233.333333 |
4 | 400 |
5 | 233.333333 |
CASE文を使った応用例
CASE文を使った応用例も見ていきましょう。
CASEを使うだけでなく、ほかの処理とも組み合わせていきます。
- CASE文を使ったソート
- 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言語を学ぶなら、登録してくことをおすすめします!
ちなみに今回のデータベース設定として、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文により、条件に応じて値を返す柔軟なクエリを作成できます。
今回学んだ知識を活かして、実際のデータベースでCASE文を使ったクエリを作成してみてください。
また、他のSQL機能やデータベース管理に関する知識も学び、スキルをさらに磨いていきましょう。