前回の高柳さんの記事に書かれた通り、SQL内でCASE式の使えないORACLE8iでは、
条件分岐にDECODE関数を使用します。
私はPL/SQLでストアドプロシージャを書くことが多いのですが、
ORACLE8iでの開発では、このDECODE関数は日付での比較の分岐や、
入れ子が複数になった場合、非常に見くいSQLが出来上がり、バグの元です。
やはり複雑になるとDECODEでは無くIF-THEN-ELSEで分岐したい。
そこでこんな場合は関数にしてしまいます。
例えば、こんな複雑な条件だとすると、
1) 区分が'1' 且つ 日付 < 期首 の金額を集計
2) 区分が'2' 且つ 期首 ≦ 日付 ≦ 期末 の金額を集計
区分が'3'の場合は金額をマイナスにして集計
3) 区分が'3'~'6'で、フラグが立っているものを集計
DECODE関数だけでのSQL:
SELECT SUM(DECODE(区分, '1',DECODE(SIGN(日付 - 期首),-1,金額
, 0)
,0))
, SUM(DECODE(区分, '2', DECODE( SIGN(日付 - 期首), -1, 0
, DECODE( SIGN(日付 - 期末) ・・・以下略
, 0)
,0))
, SUM(DECODE(区分, '2', DECODE( SIGN(日付 - 期首), -1, 0
, DECODE( SIGN(日付 - 期末) ・・・以下略
・・・と、この先を考えるのも嫌になるSQLが出来てしまいます。
PL/SQLで関数を作成するとIF-THEN-ELSEで日付の比較が可能なので、
関数の中もスッキリ見ることが出来ます。
上記の条件をGET_JOKEN関数として、区分・日付・期首・期末・フラグを渡して、
それぞれ'1'、'2'、'3'、'4'を返す関数を作成したとすると・・・
IF 区分 = '1' AND 日付 < 期首 THEN
C_RET := '1';
ELSIF 区分 = '2' AND ・・・中略
・・・
END IF;
RETURN C_RET;
C_RET := '1';
ELSIF 区分 = '2' AND ・・・中略
・・・
END IF;
RETURN C_RET;
作成した関数を使用してのSQL:
SELECT SUM(DECODE(GET_JOKEN(区分, 日付, 期首, 期末, フラグ) , '1', 金額, 0))
, SUM(DECODE(GET_JOKEN(区分, 日付, 期首, 期末, フラグ) , '2', 金額
, '3', 金額 * (-1)
, 0 ))
, SUM(DECODE(GET_JOKEN(区分, 日付, 期首, 期末, フラグ) , '4', 金額, 0))
FROM ・・・以下略
, SUM(DECODE(GET_JOKEN(区分, 日付, 期首, 期末, フラグ) , '2', 金額
, '3', 金額 * (-1)
, 0 ))
, SUM(DECODE(GET_JOKEN(区分, 日付, 期首, 期末, フラグ) , '4', 金額, 0))
FROM ・・・以下略
作成した関数が今回のこのSQLで1回しか使用しないとしても、
見やすさや今後入るかもしれない修正の為に関数にする方が有効かと思われます。