e-learning、オラクル研修、LMS(学習管理システム)のiStudy

e-learning、オラクル研修、LMS(学習管理システム)のiStudy

第113回「WEBアプリ作成(11)(チェックボックスによる複数選択処理 2/2)」

2014.12.04

こんにちは。インストラクターの蓑島です。早いもので12月になりました。

前回は、チェックボックスによる複数選択処理の入力フォーム画面を作成しました。 社員を複数選択し、給与を一律にあるパーセントで増額するための画面でしたね。
今回は、そのフォームから送信されてくるパラメータを使って選択された社員(複数)の給与を更新するプロシージャを作成し、完成させましょう。

さて、そのプロシージャ名は、「EMP_MULTI_UPDATE_EXE」でしたね。そして送信されてくるパラメータ名は「P_UP」と、「P_EMPNO」でした。
ですから今回作成するプロシージャには「P_UP」と「P_EMPNO」という二つのパラメータが宣言される必要があります。
「P_UP」は給与の増額のパーセントです。
単純に一つの値なのでVARCHAR2型で宣言します。(単純なリクエストパラメータは常にVARCHAR2型でサイズ指定はしない)
また、「P_EMPNO」は選択された社員の番号です。ですからコレクション(索引付表)でパラメータを宣言する必要があります。

そこで、索引付表などユーザが自分で定義する型をプロシージャの仮パラメータなどに使う場合、プロシージャを作成する以前にそのユーザ定義の型は宣言済みでなければいけません。
では、どこで宣言すればいいのでしょうか?
パッケージで宣言すればいいです!
パッケージはプロシージャやファンクションの枠を超えた、いわばグローバルな宣言部ということができます。(バックナンバー第33回

たとえば、PAC1というパッケージ仕様に、TYPE1という名前で索引付表の型を宣言します。

1
2
3
4
5
6
7
8
9
-- 以下のパッケージは実際には作成不要です
CREATE OR REPLACE PACKAGE  PAC1
IS
    TYPE  TYPE1 IS TABLE OF VARCHAR2(32000)
    INDEX BY BINARY_INTEGER;
END PAC1;
/
 
パッケージが作成されました。

これで、PAC1.TYPE1 という型で、パラメータを宣言できます。
しかし、このような目的のために、あらかじめ「OWA」というパッケージが用意されています。このパッケージは全ユーザが使用できるように、権限とパブリックシノニムが設定されています。そしてこのパッケージ内の「VC_ARR」という型が上記の例と同じ定義の索引付表の型です。
ですから「OWA.VC_ARR」という型で索引付表のパラメータを定義できます。

では次に、EMP_MULTI_UPDATE_EXEプロシージャの処理について考えてみましょう。
複数選択された社員の社員番号は、索引付表である「P_EMPNO」パラメータに格納されています。前回の内容を思い出していただきたいのですが、社員を一人も選択しなかった場合のエラーを防ぐために、P_EMPNOパラメータの最初の値は入力フォームの隠しパラメータで、「DUMMY」でしたね。よって社員を未選択の場合でも、このDUMMYだけは送信されてきます。
したがって「P_EMPNO」パラメータの値の数が一個しかなければ、社員は一人も選択されていないと判断できるので、その旨メッセージを表示して処理を終えてもいいわけです。
ということで、「P_EMPNO.COUNT = 1」であれば、メッセージを表示して処理を終えます。それ以外の場合は P_EMPNOの2つ目の値から最後の値までが社員番号です。 よってループ文の「 FOR I IN 2 .. P_EMPNO.LAST LOOP」などの記述により添え字「I」を「2,3,4,・・」と移動させながら、一人一人の社員の給与を更新します。

それでは以下のコーディング例をご覧ください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
CREATE OR REPLACE PROCEDURE EMP_MULTI_UPDATE_EXE
( P_UP    IN  VARCHAR2,     -- 給与増額[単位 %]
   P_EMPNO IN  OWA.VC_ARR)   -- 社員番号、ただし1個目はDUMMY
IS
   V_UP       NUMBER;
   V_SQLERRM  VARCHAR2(500);
   OSIMAI     EXCEPTION;   -- おしまいのための例外
BEGIN
    /**********************************************/
    /** 例えば、P_UPが10なら、V_UPは、1.1となる ***/
    /**********************************************/
    V_UP := 1 + TO_NUMBER(P_UP)/100;
    /**********************************************************************/
    /** 索引付表の値が一個なら、社員は選択されていないので処理を終える  */
    /**********************************************************************/
    IF P_EMPNO. COUNT = 1 THEN
       HTP.P( '社員が一人も選択されていません' );
       RAISE  OSIMAI;    -- OSIMAI例外を発生させる
    END IF;
    /**********************************************************************/
    /** 索引付表の二つ目以降が社員番号。それを取得し各社員の給与を更新する*/
    /**********************************************************************/
    FOR I IN  2..P_EMPNO. LAST LOOP
        UPDATE EMP                        -- 該当社員番号の社員の給与を更新
        SET SAL = SAL * V_UP
        WHERE EMPNO = TO_NUMBER(P_EMPNO(I));
        IF SQL%ROWCOUNT <> 1 THEN        -- 念のためのチェック
           ROLLBACK ;
           HTP.P( '異常です。処理を取り消します' );
           RAISE OSIMAI;
        END IF;
    END LOOP;
    COMMIT ;
    HTP.P( '正常に更新できました' );
EXCEPTION
    WHEN OSIMAI  THEN   -- おしまいにすることだけが目的の例外ハンドラ
         NULL ;
    WHEN OTHERS THEN
         V_SQLERRM := SQLERRM;
         HTP.P(V_SQLERRM);
END EMP_MULTI_UPDATE_EXE;
/
 
プロシージャが作成されました。

では解説します。

まず、一般に前画面で手入力だったパラメータは処理に入る前にチェックが必要です。(12行目)すなわち、給与の増額割合はP_UPパラメータですが、仮に数値以外の値であればTO_NUMBER関数がエラーとなります。よって38~40行目の例外ハンドラでエラーメッセージを表示し処理を終わらせることができます。
正常にNUMBER型に変換できれば、V_UP変数(5行目で宣言)に係数が格納されますので、後の更新処理で使います。
コメントにありますように、P_UPの値が10であれば、10%増額ということで、1.1を係数にすればよいわけです。上記のコードでは考慮していませんが、できることなら、P_UPがNULLだったり、増分%として不適切な値であれば処理を終わらせるような細かい考慮をすべきところです。

また、13~19行目は前述したように、索引付表の値の個数が1個であれば社員が未選択なので「社員が一人も選択されていません」というメッセージを表示して処理を終わらせています。ここで処理の終わらせ方ですが、お分かりと思いますが、7行目でOSIMAIというユーザ定義例外を宣言し、18行目のRAISE文でその例外を発生させます。そして、36-37行目のOSIMAI例外ハンドラに遷移します。ここで何もせず(NULL;)単純に処理を終えているわけです。
このようにユーザ定義例外は必ずしもエラー処理でななく、他の目的でも使用できます。

また20行目から34行目までは社員が選択されていた場合の処理です。
23行目(FOR I IN 2..P_EMPNO.LAST LOOP)の記述にあるように、添え字「I」は2からはじまり、最後の添え字まで順番に移動しながらループします。そしてそれぞれの添え字番号で索引付表の値「P_EMPNO(I)」の社員番号で、その社員の給与に前述の V_UPの係数をかけて更新します。

27~31行目は念のためのチェックです。
というのも、前画面で社員選択に使ったチェックボックスはPL/SQLのプログラムロジックで生成していますから、存在する社員番号で1行が更新されるはずです。しかし仮に1行でない場合は異常として、ROLLBACKして処理を取り消しています。

そして最後まで処理できれば、33行目で確定(COMMIT;)し、「正常に更新できました」というメッセージを表示して処理を終わらせています。

では早速、実行してみましょう。まず、前回の入力フォーム画面を開きましょう。

前回と同じなので、
http://localhost:8080/dad/emp_multi_update_form

ログインを求められたら、SCOTTユーザとパスワードを入力します。

前回と同じように2行選択し、増分を10%とします。

そして、送信ボタンをクリックすると・・「正常に更新できました」のメッセージが表示されます。

もう一度、入力フォーム画面を開くと、たしかに選択した2行の給与が10%増額されました。

いかがですか?
複数選択処理は便利な機能です。ぜひこのパターンをマスターしてください。

なお、複数選択処理では「すべて選択」とか、「すべて解除」といった機能が画面に備わっている場合があります。そのような追加機能は、JavaScriptなどを使えば簡単に対応できます。本メルマガのWEBプロシージャではすべてHTP.P(~)によりHTMLを生成しているだけなので、その内容にJavaScriptを反映させればどのようなJavaScriptの機能でも盛り込むことができます。JavaScriptに興味のある方は、調べてどんどんと発展させてみてください。

それでは今回はここまでです。また、次回ご期待ください。

先頭へ戻る