【SQL超入門講座】21.CASE|条件に合わせて処理を分ける方法

sql21
SQL超入門講座

こんにちはキノコードです。
皆さんはSQLでカラムの値に応じて異なる値を入力したり、フラグを立てたりしたい時がありませんか?
例えば、生徒のテストの点数が記録されたこちらのテーブルを見てください。
合否のカラムを作成し、生徒のテストの点数が3点以上であれば合格、それ以外は不合格と入力します。
このような時、どのように入力すればいいと思いますか?
プログラミングを学習したことがある人は、If Else構文による条件分岐を思いつくのではないでしょうか?
SQLではIf Else構文のような条件分岐を、Case式を使って行うことができます。
今回、例として出した点数に応じた合否の入力も、Case式を使えば簡単です。
Case式を覚えることで、複雑な条件にも対応できるようになりますので、是非使いこなせるようになりましょう。
なおキノコードでは、この動画の他にもたくさんのプログラミングの動画を発信しています。
チャンネル登録がまだの方は、チャンネルがどこに行ったか分からなくならないように、是非チャンネル登録をお願いします。
それではレッスンスタートです。

この記事の執筆・監修

キノコード
キノコード

テクノロジーアンドデザインカンパニー合同会社のCEO。
日本最大級のプログラミング教育のYouTubeチャンネル「キノコード」や、プログラミング学習サービス「キノクエスト」を運営。
著書「あなたの仕事が一瞬で片付くPythonによる自動化仕事術」や、雑誌「日経ソフトウエア」や「シェルスクリプトマガジン」への寄稿など実績多数。

プログラミング学習サービス「キノクエスト」のご紹介

キノコードでは、プログラミングを習得するためのプログラミング学習サービス「キノクエスト」を運営しています。
Pythonの問題の他に、SQLの問題も120問以上あります。
キノクエストには、学習カリキュラムがあり、学習順番に悩むことなく学習を進められます。
月額1,990円と本1冊分の値段です。

キノクエストの特徴は下記の通りです。

  • SQLの問題も120問以上
  • プログラミング学習をしている仲間が集まるコミュニティがある
  • 1000問以上の問題を解いてプログラミングを習得
  • 環境構築不要ですぐに始められる
  • 動画と連動しているので、インプットもできる。
  • 月額1,990円で、コミュニティもセット

キノクエストを詳しく知りたい方は、紹介ページをご覧ください。

▼キノクエストの紹介ページはこちら▼
https://kino-code.com/kq_service_a/

それでは、レッスンスタートです。

CASE式とは

SQLでIF ELSEのような条件分岐を行いたいときはCASE式を使用します。
CASE式には単純CASE式と検索CASE式の2種類があります。

単純CASE式ではカラムの値が指定した値と等価であるかを判定し、処理の分岐を行います。
一方で検索CASE式は、等価判定以外にもさまざまな条件で処理を分岐させることができます。

最初に単純CASE式と検索CASE式の構文を確認しておきましょう。

まず単純CASE式の構文を確認します。

CASE カラム
    WHEN 値1 THEN 結果1
    WHEN 値2 THEN 結果2
    ・
    ELSE 結果3
END

単純CASE式では、まずCASEと書いた後に対象となるカラムを書きます。
続くWHEN句からELSE句でカラムの値に基づき処理を分岐します。
WHEN句で値を指定し、その値がカラムの値と等価である場合に返す結果を、THENの後に書きます。
等価でない場合に行う別の処理を、次のWHEN句に書いていきます。
そしてカラムの値が、WHEN句で指定した値のいずれにも一致しない場合に返す結果を、ELSE句に書きます。
最後にENDを書きCASE式を終了します。
単純CASE式については以上となります。

次に検索CASE式の構文を確認します。

CASE
    WHEN 条件式1 THEN 結果1
    WHEN 条件式2 THEN 結果2
    ・
    ELSE 結果3
END

構造は単純CASE式と似ていますが、検索CASE式と単純CASE式ではいくつかの違いがあります。
一つ目の違いは、CASEの後に条件分岐の対象となるカラムを書かないことです。
二つ目の違いは、WHEN句で条件式を書いて、この条件式が真のときに返す結果をTHENの後に書くことです。

検索CASE式は単純CASE式と比べてより複雑な条件に基づいて分岐を行うことができ、単純CASE式を書き換えることもできます。
そのため検索CASE式だけを覚えていれば、条件分岐は問題ないように感じるかもしれません。
ただ単純CASE式も等価判定による条件分岐を可読性高く記述できる点では有用です。
是非単純CASE式と検索CASE式はどちらもしっかりと覚えておくようにしましょう。

CASE式の使い方

ここからは具体的にテーブルを用いて、使い方を確認していきます。
まずデモテーブルのtest01を作成します。
test01は氏名、出席番号、数学の3つのカラムを持ったテーブルです。

氏名 出席番号 数学
高橋 a001 1
伊藤 a002 2
鈴木 a003 3
佐藤 a004 4

それでは数学の点数に基づいて成績を割り振りってみましょう。
成績の割り振りは数学の点数が、1であればC、4であればA、それ以外であればBとします。

単純CASE式を使う場合、次のようにSQLを書くことができます。

SELECT * ,
    CASE 数学
        WHEN 1 THEN 'C'
        WHEN 4 THEN 'A'
        ELSE 'B'
    END 成績
FROM test01

CASEの後に条件分岐の対象となる数学のカラムを書きます。
続くWHEN句からELSE句で数学の値に基づいて処理の分岐を行います。
WHEN句では、まず数学の値が1のとき、4のときで分岐を行い、それぞれ割り振られる成績CとAをTHENの後に書きます。
そして数学の値が1と4のどちらでもない場合に、一律で割り振られる成績BをELSE句に書きます。
最後にENDを書いてCASE式を終了させます。  

CASE式で取得するカラムに別名をつける場合は、ENDのあとに書きます。
ここでは別名をそのまま「成績」としています。

それではSQLを実行します。

氏名 出席番号 数学 成績
高橋 a001 1 C
伊藤 a002 2 B
鈴木 a003 3 B
佐藤 a004 4 A

「成績」のカラムに数学の点数に基づいて正しく成績が割り振ることができました。

検索CASE式を使うと、同じ条件分岐を次のように書くことができます。

SELECT * ,
    CASE
        WHEN 数学 = 1 THEN 'C'
        WHEN 数学 = 4 THEN 'A'
        ELSE 'B'
    END 成績
FROM test01

検索CASE式で書く場合は、CASEの後にカラムを書かず、WHEN句に等価判定の条件式を書きましょう。
実行します。

氏名 出席番号 数学 成績
高橋 a001 1 C
伊藤 a002 2 B
鈴木 a003 3 B
佐藤 a004 4 A

単純CASE式と意味する内容が同じなので、実行結果はこの通り同じになります。

今度は別のテーブルを使って、先ほどと異なる条件で処理の分岐を行ってみたいと思います。
使用するtest_tableはこのようなカラムを持った、注文データのテーブルです。

index 売上日 社員ID 商品分類 商品名 単価 数量 売上金額
1 2020/1/4 a023 ボトムス ロングパンツ 7000 8 56000
2 2020/1/5 a003 ボトムス ジーンズ 6000 10 60000
3 2020/1/5 a052 アウター ジャケット 10000 7 70000
4 2020/1/6 a003 ボトムス ロングパンツ 7000 10 70000

test_tableの売上金額に応じてキャッシュバックが行われると仮定します。
売上金額に応じたキャッシュバックの金額は次の通りで、売上金額が大きいほど、キャッシュバックの金額も大きくなるように設定されています。
この時、他のカラムと一緒にキャッシュバックの金額を示すカラムを抽出してみましょう。

売上金額 キャッシュバック
100,000円以上 10,000円
50.000円以上10,0000円未満 3,000円
50,000円未満 1,000円

今回は「売上金額が何円以上何円以下の範囲内にあるか」という条件に基づき処理を分岐させます。
等価判定しかできない単純CASE式は使用できないので、検索CASE式を使用します。 

SQLは次のように書くことができます。
  

SELECT * ,
    CASE
        WHEN 売上金額 >= 100000 THEN 10000
        WHEN 売上金額 >= 50000 THEN 3000
        ELSE 1000
    END キャッシュバック
FROM test_table

WHEN句で売上金額が100,000円以上のとき、50,000円以上のときで分岐を行い、それぞれ適用されるキャッシュバックの金額をTHENの後に書きます。
WHEN句は上から順に評価されるので、2つ目のWHEN句が評価されるとき、売上金額は100,000円未満であることが確定しています。
そのため2つ目のWHEN句は「売上金額が50,000円以上100,000円未満のとき」という意味になります。
そして売上金額が50,000円未満の場合はキャッシュバックの金額が一律で1,000円となりますので、ELSE句に1000と書きます。
最後にENDを書きCASE式を終了します。
カラムの別名はそのまま「キャッシュバック」としました。

それではSQLを実行して、正しく条件分岐が行われるか確認してみましょう。

index 売上日 社員ID 商品分類 商品名 単価 数量 売上金額 キャッシュバック
1 2020/1/4 a023 ボトムス ロングパンツ 7000 8 56000 3000
2 2020/1/5 a003 ボトムス ジーンズ 6000 10 60000 3000
3 2020/1/5 a052 アウター ジャケット 10000 7 70000 3000
4 2020/1/6 a003 ボトムス ロングパンツ 7000 10 70000 3000
5 2020/1/7 a036 ボトムス ロングパンツ 7000 2 14000 1000

売上金額に応じて、正しくキャッシュバックの金額を計算して、カラムとして抽出することができました。

CASE式を入れ子にして使う

最後にCASE式を入れ子にして使う方法を確認しましょう。
先ほどのキャッシュバックが1月限定のキャンペーンだったと仮定します。  
このとき、まず売上日に基づく条件分岐を行います。
そして売上日が1月中である売上に対してのみ、売上金額に基づく条件分岐を行いキャッシュバックの金額を求めます。

このように1つの条件分岐の中で、更に別の条件分岐を行う場合 、CASE式を入れ子にSQLを書きます。
今回の場合は、SQLを次のように書くことができます。

SELECT * ,
    CASE
        WHEN 売上日 BETWEEN '2020-01-01' AND '2020-01-31' THEN
            CASE
                WHEN 売上金額 >= 100000 THEN 10000
                WHEN 売上金額 >= 50000 THEN 3000
                ELSE 1000
            END
        ELSE 0
    END キャッシュバック
FROM test_table

最初のCASE式で売上日が1月中のとき、それ以外のときで分岐を行います。
WHEN句で売上日が1月中のときは、THENの後にさらにCASE式を書いて売上金額に基づく分岐を行います。
売上金額に基づく分岐については、先ほど説明した通りなので割愛します。
そして売上日が1月中でないときは、キャッシュバックが行われないのでELSE句に0を書きます。
最後にCASE式を終了するENDを書きます。

それではSQLを実行してみましょう。

index 売上日 社員ID 商品分類 商品名 単価 数量 売上金額 キャッシュバック
1 2020/1/4 a023 ボトムス ロングパンツ 7000 8 56000 3000
2 2020/1/5 a003 ボトムス ジーンズ 6000 10 60000 3000
3 2020/1/5 a052 アウター ジャケット 10000 7 70000 3000
4 2020/1/6 a003 ボトムス ロングパンツ 7000 10 70000 3000
5 2020/1/7 a036 ボトムス ロングパンツ 7000 2 14000 1000
20 2020/2/2 a003 ボトムス ロングパンツ 7000 4 28000 0
21 2020/2/3 a036 トップス シャツ 4000 5 20000 0
22 2020/2/3 a047 アウター ダウン 18000 8 144000 0

売上日が1月中のレコードには、キャッシュバックのカラムに正しいキャッシュバックの金額が入力されています。
そして売上日が2月以降のレコードには全て0が入力されています。
正しく条件分岐を行うことができたようです。

レッスンは以上です。
CASE式を使うことで、さまざまな条件に基づいてデータを取得できるようになりますので、是非使い方をマスターしてくださいね。

Kinocodeではわかりやすく飽きない動画づくりを意識しています。
今後はこのようなレッスン動画の配信を予定しています。
レッスンの新着通知が行きますので、是非チャンネル登録をお願いします。
それでは、次のレッスンでお会いしましょう。

SQL21(case).md
SQL21(case).md を表示しています。