Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


SQLで条件分岐する方法(CASE式) DB2 for IBMi

SQLで条件分岐するには、CASE式を使用します。
CASE式を使用することで、プログラム言語と似たようにSQLでも条件分岐を記述することができます。
Tipsでは、DB2 for IBMiのデータベースで、CASE式による様々な条件分岐方法をご紹介します。

CASE式とは?

SQLの中で条件分岐が記述できればと思ったことはないでしょうか。
CASE式を利用すると、プログラムを作成するように条件分岐を記述することが可能です。
CASE式は「条件」により出力する「結果」を変えたい場合に使用します。

また、CASE式には、単純CASE式、検索CASE式があり少し記述が異なります。
さらに、CASE式は、SELECT文節だけでなく、WHERE文節やUPDATE文節でも使用可能です。
今回のTipsでは、SQLの記述例を踏まえながらご紹介いたします。

なお、CASE式については以下、IBMのサイトもご確認ください。

■CASE式
https://www.ibm.com/docs/ja/i/7.3?topic=expressions-case-expression

単純CASE式と検索CASE式

SAMPLEライブラリに以下のような顧客ファイル(CUSTOMER)が存在する場合を例とします。

CUSTCD(顧客CD)CUNAME(顧客名)CUGEND(性別)CUAGE(年齢)CURANK(ランク)CUPONT(ポイント)
C0001山田 太郎050C48000
C0002山田 花子144C13000
C0003三我路 春男025C26000
C0004三我路 夏子115C35000

単純CASE式の例

単純CASE式はわかり易い記述が可能です。しかし、実現できることが限定的です。
単純CASE式は特定フィールドの値が一致した場合に、出力する式を変化させる際に使用します。

例えば、性別コード(CUGEND)の値によって出力する結果の文字を変えたい場合には以下のように記述します。

SELECT CUNAME,
       CASE CUGEND
           WHEN '0' THEN '男性'
           WHEN '1' THEN '女性'
           ELSE '不明'
       END AS "GENDER"
    FROM SAMPLE.CUSTOMER

CASEの後に条件となるフィールド名(条件)を記述して、WHENでCASE後に設定されたフィールド名の値によって条件分岐します。
THEN 以降に記述された式が結果として出力されます。
例では、文字列で「男性、女性、不明」のいずれかを出力することになります。
ELSEは条件に設定された値が’0’でも’1’でもない場合に出力されます。
また、CASE式ではELSEの条件を省略可能です。

結果

CUNAME(顧客名)GENDER(性別)
山田 太郎 男性
山田 花子女性
三我路 春男男性
三我路 夏子女性

検索CASE式の例

実際にSQLで条件分岐を記述する場合、単純な一致だけでなく条件式により判別することが多いと思います。条件式を使用する場合には検索CASE式を使用します。

例えば、年齢(CUAGE)の値によって、各年代の結果を出力する場合には以下のように記述します。

SELECT CUNAME,
       CASE WHEN CUAGE < 20 THEN '20才未満'
            WHEN CUAGE < 40 THEN '20代~30代'
            WHEN CUAGE < 60 THEN '40代~50代'
           ELSE '60代以降'
       END AS "GENERATION"
    FROM SAMPLE.CUSTOMER

条件式にすることで、単純な一致だけでなく、条件指定して条件分岐が可能となります。
また、CASE式では上部の条件に一致した段階で、条件の処理は打ち切られて下部の条件は考慮されません。そのため、CUAGEが15であった場合、「CUAGE < 40」や「CUAGE < 60」も条件に一致しますが、上部に記述された、CUAGE < 20の条件に一致した段階で条件分岐処理が終了します。

結果

CUNAME(顧客名)GENERATION(世代)
山田 太郎40代~50代
山田 花子40代~50代
三我路 春男20代~30代
三我路 夏子20才未満

SELECT文節のCASE式 その他の使い方

CASE式と集計関数

CASE式は集計関数と組み合わせて使用することも可能です。
例えば、SAMPLE.CUSTOMERファイルから年齢が20才以上となる人数をカウントする場合に、CASE式を使うのであれば、以下のような記述となります。

SELECT SUM(
        CASE
            WHEN CUAGE >= 20 THEN 1
            ELSE 0
        END) AS "OVER20"
    FROM SAMPLE.CUSTOMER

結果

OVER20(20才以上)
3

もちろん、本例のような、20才以上の人数を取得する際、CASE式を使わなくても取得することができますが、集計関数内でCASE式が利用できることを認識ください。

条件の連結

検索CASE式で複数のフィールドを条件に記述したい場合、AND や ORで連結した条件を作成することも可能です。

例えば、「20才以上」かつ「ポイントを5000以上」保持しているユーザー名には、結果フィールドのフラグに1を設定する場合、ANDで条件を連結することで表現することができます。

SELECT CUNAME,
       CASE
           WHEN CUAGE >= 20 AND CUPONT >= 5000 THEN '1'
           ELSE '0'
       END AS "OVER20_POINT5000"
    FROM SAMPLE.CUSTOMER

結果

CUNAME(顧客名)OVER20_POINT5000(20以上5000ポイント以上保持)
山田 太郎1
山田 花子0
三我路 春男1
三我路 夏子0

複数条件の記述(INの使用)

複数の条件を指定する場合、IN述部を使用することも可能です。
例えば、会員のランクが「C3,C4,C5」の場合は「プレミア会員」、「C1,C2」の場合は「一般会員」と出力する場合には以下となります。

SELECT CUNAME,
       CASE
           WHEN CURANK IN ('C3', 'C4', 'C5') THEN 'プレミア会員'
           WHEN CURANK IN ('C1', 'C2') THEN '一般会員'
       END AS "KUBUN"
    FROM SAMPLE.CUSTOMER

結果

CUNAME(顧客名)KUBUN(区分)
山田 太郎プレミア会員
山田 花子一般会員
三我路 春男一般会員
三我路 夏子プレミア会員

■IN述部
https://www.ibm.com/docs/ja/i/7.3?topic=predicates-in-predicate

CASE文の入れ子

CASE式は入れ子にすることも可能です。
条件分岐(CASE式)の中に更なる条件分岐(CASE式)を記述することができます。

以下では、「プレミア会員」かつ ポイントを5001以上保有している場合、5000以下の場合、「一般会員」かつ ポイントを5001以上保有している場合、5000以下の場合を条件分岐で表現しています。

SELECT CUNAME,
       CASE
           WHEN CURANK IN ('C3', 'C4', 'C5') THEN 
             CASE WHEN CUPONT > 5000 THEN 'プレミア会員ポイント5001以上'
             ELSE 'プレミア会員ポイント5000以下' 
             END
           WHEN CURANK IN ('C1', 'C2') THEN
             CASE WHEN CUPONT > 5000 THEN '一般会員ポイント5001以上'
             ELSE '一般会員ポイント5000以下' 
             END             
       END AS "KUBUN"
    FROM SAMPLE.CUSTOMER

結果

CUNAME(顧客名)KUBUN(区分)
山田 太郎プレミア会員ポイント5001以上
山田 花子一般会員ポイント5000以下
三我路 春男一般会員ポイント5001以上
三我路 夏子プレミア会員ポイント5000以下

条件指定(Where文節)での使用例

条件指定(Where文節)中にCASE式を使用することも可能です。
Where文節にCASE式を使用することで複雑な検索結果を取得することができます。
以下例ではWhere文節でCASE式を利用して、「ポイントが5000以上」、「顧客名が’三’から始まり」 かつ 「会員ランクがC2」と「ポイントが5000以下」の顧客名一覧を出力します。

SELECT CUNAME
    FROM SAMPLE.CUSTOMER
    WHERE 1 = (
        CASE WHEN CUPONT >= 5000 THEN (
             CASE WHEN CUNAME LIKE '三%' AND CURANK = 'C2' THEN 1
             ELSE 0
             END)
           ELSE 1
        END)

 ※CASE式の結果で1を返却して、同じ1と比較することで、一致条件に含めています。

結果

CUNAME(顧客名)
山田 花子
三我路 春男

上記のSQLの場合は、通常のWHERE文節でも記述することができます。
CASE式を利用すると、ELSE(条件以外)の分岐ができるため直感的にわかり易く記述できる場合もあると思います。

CASE式を利用しない場合の例

SELECT CUNAME
    FROM SAMPLE.CUSTOMER
    WHERE ((CUPONT >= 5000
                AND (CUNAME LIKE '三%'
                    AND CURANK = 'C2'))
            OR CUPONT < 5000)

更新時のCASE式使用例

CASE式はUPDATE文節にも使用することができます。
以下では 「会員ランクが C5」の場合は、現在保有ポイントの15%をポイントに追加
「会員ランクがC4」の場合は、保有ポイントの10%をポイントに追加 、 「会員ランクがC3」の場合は保有ポイントの5%をポイントに追加するSQLです。

UPDATE SAMPLE.CUSTOMER
    SET CUPONT = CUPONT +
            CASE
                WHEN CURANK = 'C5' THEN INT(CUPONT * 0.15)
                WHEN CURANK = 'C4' THEN INT(CUPONT * 0.10)
                WHEN CURANK = 'C3' THEN INT(CUPONT * 0.05)
                ELSE 0
            END

UPDATEの実行後、SQLにて各ユーザーのポイントを確認すると以下になります。

 SELECT CUNAME ,CURANK ,CUPONT FROM SAMPLE.CUSTOMER 

UPDATE前

CUNAME(顧客名)CURANK(ランク)CUPONT(ポイント)
山田 太郎C48000
山田 花子C13000
三我路 春男C26000
三我路 夏子C35000

UPDATE後

CUNAME(顧客名)CURANK(ランク)CUPONT(ポイント)
山田 太郎C48800
山田 花子C13000
三我路 春男C26000
三我路 夏子C35250

おわりに

今回のTipsでは、CASE式についてご紹介しました。
Valenceのデータソース作成時等、SQLを入力して定義する際、CASE式を使用するとSQL内で条件分岐で結果を返すことが可能になりますので是非ご活用ください。