タイトルロゴ

記載日 2006/02/28
はじめに

 PL/SQLでは、IF文などの条件式において「IN演算子」を使用することができます。

 例えば以下の様に、整数変数が、1、2、4のいずれかに等しいことを判別する条件式は、 IN演算子を使用した記載方法が最もコーディングしやすいですし、見やすいので保守性も上がります。

大小比較   IF 変数 >= 1 AND 変数 <= 4 AND 変数 != 3 THEN

            ・・・
  END IF;
OR演算子   IF 変数 = 1 OR 変数 = 4 OR 変数 = 2 THEN

            ・・・
  END IF;
IN演算子   IF 変数 IN ( 1, 2, 4 ) THEN

            ・・・
  END IF;



 しかし、一つのパッケージ内の複数のプロシジャー/ファンクションで、上の条件が点在しているとしましょう。 変数のとりうる値を変更したい場合、全ての箇所を修正するのは手間ですし、修正漏れも発生しかねません。

 そこで、思い切ったことではありますが、パッケージ内のプロシジャー/ファンクション のIF文でINを使用しないことを提案したいと思います。



セクション







検証環境

 
ページのTOPへ

 PL/SQLパッケージ内には、複数のプロシジャー/ファンクションを記載できます。 そもそも、パッケージは、プロシジャー/ファンクションを論理的なグループにま とめる意味で作成されます。それゆえ、似たような分岐処理が点在することが多いはずです。

 コーディング規約無しで複数人でプロシジャー/ファンクションの作成を分担し、 それを切り貼りで一つのパッケージにまとめる場合などは、同じ分岐処理でも、様々な 記載方法が存在することになるでしょう。

 下の SAMPLE_PACKAGEパッケージ は、同じ条件分岐が点在しているパッケージの例を 示したものです。

 変数が'01', '02', '04'のいずれかに等しいかどうかを判別していますが、 変数の候補値に他の値が追加される場合や、逆に候補値から'02'を対象外にすることになった場合、 このパッケージには合計四箇所の修正が発生します。

/* -------------------------------- */
/* サンプルパッケージ定義           */
/* -------------------------------- */
CREATE OR REPLACE PACKAGE SAMPLE_PACKAGE
AS
    /* ------------------------------- */
    /* ファンクション1                 */
    /* ------------------------------- */
    FUNCTION FUNC_1;

    /* ------------------------------- */
    /* ファンクション2                 */
    /* ------------------------------- */
    FUNCTION FUNC_2;

    /* ------------------------------- */
    /* プロシジャー1                   */
    /* ------------------------------- */
    PROCEDURE PRO_1;

END SAMPLE_PACKAGE;
/
CREATE OR REPLACE PACKAGE BODY SAMPLE_PACKAGE
AS
    /* ------------------------------- */
    /* ファンクション1                 */
    /* ------------------------------- */
    FUNCTION FUNC_1
    RETURN NUMBER
    IS
    BEGIN
        ・・・
        IF VALUE IN ( '01', '02', '04' ) THEN
        ・・・
    END FUNC_1;

    /* ------------------------------- */
    /* ファンクション2                 */
    /* ------------------------------- */
    FUNCTION FUNC_2
    RETURN NUMBER
    IS
    BEGIN
        ・・・
        IF WK_VALUE IN ( '01', '02', '04' ) THEN
        ・・・
        IF WK_VALUE NOT IN ( '01', '02', '04' ) THEN
        ・・・
    END FUNC_2;

    /* ------------------------------- */
    /* プロシジャー1                   */
    /* ------------------------------- */
    PROCEDURE PRO_1
    IS
    BEGIN
        ・・・
        IF NUM = '01' OR NUM = '02' OR NUM = '04' THEN
        ・・・
    END PRO_1;

END SAMPLE_PACKAGE;
/


 
ページのTOPへ

 そこで、下記の様にパッケージ初期化部を利用した実装方法を提案します。 パッケージ初期化部とは、パッケージ本体にパッケージレベルのBEGIN〜ENDを 記載したものです。セッションで最初にパッケージが呼ばれたときに一度きり実行されます。

 まず、パッケージ仕様部で、VARCHAR2(100)の配列をVARCHAR2(2)の索引付きで 作成します。VARCHAR2(100)の「100」には特に意味がありません。コードの補足説明に使用するエリア として使用します。重要なのは、VARCHAR2(2)の索引部分です。索引付き配列 には、EXISTSメソッドが用意されています。使用方法は以下の様になります。

  配列.EXISTS(索引)
           → 索引に対応する配列要素が有れば TRUE を返します。

           → 索引に対応する配列要素が無ければ FALSE を返します。


 この配列.EXISTSメソッドを利用することで、条件式の今後の変更に柔軟に対応できる パッケージになるはずです。もし条件式の候補値に変化があっても、パッケージ初期化部のコードのみを編集することで 事足ります。
 
/* -------------------------------- */
/* サンプルパッケージ定義           */
/* -------------------------------- */
CREATE OR REPLACE PACKAGE SAMPLE_PACKAGE
AS
    /* ------------------------------- */
    /* 索引付き配列を宣言              */
    /* ------------------------------- */
    TYPE TYPE_CODE_LIST IS TABLE OF VARCHAR2(100)
        INDEX BY VARCHAR2(2);
    AREA_CODE_LIST  TYPE_CODE_LIST;  /* 処理対象となるエリアコードのリスト */
    
    /* ------------------------------- */
    /* ファンクション1                 */
    /* ------------------------------- */
    FUNCTION FUNC_1;

    /* ------------------------------- */
    /* ファンクション2                 */
    /* ------------------------------- */
    FUNCTION FUNC_2;

    /* ------------------------------- */
    /* プロシジャー1                   */
    /* ------------------------------- */
    PROCEDURE PRO_1;

END SAMPLE_PACKAGE;
/
CREATE OR REPLACE PACKAGE BODY SAMPLE_PACKAGE
AS
    /* ------------------------------- */
    /* ファンクション1                 */
    /* ------------------------------- */
    FUNCTION FUNC_1
    RETURN NUMBER
    IS
    BEGIN
        ・・・
        IF AREA_CODE_LIST.EXISTS(VALUE) THEN
        ・・・
    END FUNC_1;

    /* ------------------------------- */
    /* ファンクション2                 */
    /* ------------------------------- */
    FUNCTION FUNC_2
    RETURN NUMBER
    IS
    BEGIN
        ・・・
        IF AREA_CODE_LIST.EXISTS(WK_VALUE) THEN
        ・・・
        IF NOT AREA_CODE_LIST.EXISTS(WK_VALUE) THEN
        ・・・
    END FUNC_2;

    /* ------------------------------- */
    /* プロシジャー1                   */
    /* ------------------------------- */
    PROCEDURE PRO_1
    IS
    BEGIN
        ・・・
        IF AREA_CODE_LIST.EXISTS(NUM) THEN
        ・・・
    END PRO_1;

/* パッケージの初期化部 */
BEGIN
    /* ここで、パッケージの初期化処理として配列に値をつめます。 */
    /* 配列の索引部分に意味があり、'北海道'、'青森'、'岩手'は、 */
    /* 特に意味がありません。補足メッセージ扱いです。           */
    AREA_CODE_LIST('01') := '北海道';
    AREA_CODE_LIST('02') := '青森';
    AREA_CODE_LIST('04') := '岩手';
END SAMPLE_PACKAGE;
/


 
ページのTOPへ
 私がここで提案したかったことは、IN演算子を使用した条件式は索引付き配列のEXISTSメソッドを 使用してみてはどうだろうかと言う、ただそれだけのことです。強要するものでは有りません。
 しかし、コーディング規約として、変数の命名方法や、改行、インデントの付け方 を決めるなら、この様に処理の組立て方なども規約に載せたいところです。