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

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

第110回「WEBアプリ作成(8)データ更新(UPDATE)(1/2)」

2014.11.13

前回までで、データを登録したり(バックナンバー第107108回)、そのデータを表示したり(第109回)するWEBアプリの作成を解説してきました。
そして登録されたデータは、必要があれば、もちろん更新することも可能でなければなりません。

ということで、今回は、既存のデータを更新(UPDATE)するWEBアプリを作成したいと思います。

前回と同じく、EMP2表を対象にします。

データの更新も、登録と同じように、入力用のフォーム画面とそのフォームのデータでデータベースを更新する処理の二つが必要です。それぞれ別のプロシージャで作成します。
データ更新(UPDATE)のためのフォーム画面は、更新対象となるレコード(表の行)を読み込む必要があります。その点がデータ登録(INSERT)の場合のフォームと大きく違います。
データ登録のフォーム画面は開いたときに何のデータもない空の状態で結構ですが、データ更新の場合は、開いたときなどにデータを読み込んだ状態が必要です。
データを読み込むにはSELECT文です。通常、1レコードであれば、SELECT~INTO文です。
ではSELECT~INTO文などで取得したレコードを、フォームの入力項目に読み込ませるにはどうすればいいのでしょうか?

例えば、データ登録(INSERT)のときの空のフォームでは入力項目の記述は以下のようなタグでした。(バックナンバー 第107回)

1行のテキスト     ⇒  <INPUT TYPE="TEXT" NAME="パラメータ名">

複数行のテキスト   ⇒ <TEXTAREA NAME="パラメータ名"></TEXTAREA>
選択リストボックス ⇒ <SELECT NAME="パラメータ名"><OPTION VALUE="値1">表示1</OPTION>
                                                    <OPTION VALUE="値2">表示2</OPTION>
                                                    ・・・・・・・
                                                     </SELECT>

ではこれらのタグがデータを読み込んだ状態でフォームを開くには、プロシージャはどのようなタグを生成すればいいのでしょうか?

それはたいへん簡単であり、値を含んだ状態でのタグを生成すればよいのです。
具体的には次のようにです。青でハイライトした部分に注目してください。

1行のテキスト     ⇒  <INPUT TYPE="TEXT" NAME="パラメータ名" VALUE="値">

複数行のテキスト   ⇒ <TEXTAREA NAME="パラメータ名">~値~</TEXTAREA>

選択リストボックス ⇒ <SELECT NAME="パラメータ名"><OPTION VALUE="値1">表示1</OPTION>
                                                    <OPTION VALUE="値2" SELECTED>表示2</OPTION>
                                                    ・・・・・・・
                                                     </SELECT>

上記のようなタグを生成するとフォーム画面が開いたときにその値が反映された(読み込まれた)状態となります。

ご覧のように、1行のテキストの場合は、「VALUE="値"」で指定し、複数行テキストの場合は、テキストエリアの開始タグ<TEXTAREA ・・・>と終了タグ</TEXT>の間にある文字が値となります。

選択リストボックスは、「SELECTED」の指定があるOPTIONが、フォームが開いたときに選択されているリスト項目です。
つまり読み込んだレコードの値に応じて、該当する値のOPTIONタグに対して、SELECTEDという指定をすればよいのです。

それでは早速、EMP2表の行を更新するためのフォーム、EMP2_UPDATE_FORMプロシージャを作成します。データ登録のフォーム EMP2_INSERT_FORMプロシージャと似ています。以下のようなコードです。

  1  create or replace
  2   PROCEDURE EMP2_UPDATE_FORM (P_EMPNO IN VARCHAR2)
  3   IS
  4     V_DEPT  VARCHAR2(1000);
  5     REC     EMP2%ROWTYPE;   -- 該当レコードを読み込むレコード変数
  6   BEGIN
  7   /*******************************************/
  8   /*-部門のリストを生成する------------------*/
  9   /*******************************************/
 10     V_DEPT  := '<SELECT NAME="P_DEPTNO"><OPTION VALUE="NULL">-</OPTION>';
 11     FOR REC IN (SELECT * FROM DEPT ORDER BY DEPTNO) LOOP
 12         V_DEPT := V_DEPT || '<OPTION VALUE="' ||TO_CHAR(REC.DEPTNO) ||'">' ||
 13                                    REC.DNAME ||'</OPTION>';
 14     END LOOP;
 15     V_DEPT := V_DEPT || '</SELECT>';
 16   /*******************************************/
 17   /*-更新対象の行を取得する------------------*/
 18   /*******************************************/
 19     SELECT * INTO REC FROM EMP2 WHERE EMPNO = TO_NUMBER(P_EMPNO);
 20   /*******************************************/
 21   /*-部門リストの該当値を選択された状態にする*/
 22   /*******************************************/
 23     V_DEPT := REPLACE(V_DEPT,'VALUE="' ||TO_CHAR(REC.DEPTNO) ||'"',
 24                              'VALUE="' ||TO_CHAR(REC.DEPTNO) ||'" SELECTED');
 25   -- ここから画面表示処理
 26     HTP.P('<HTML>');
 27     HTP.P('<HEAD><TITLE>社員登録</TITLE></HEAD>');
 28     HTP.P('<BODY>');
 29     HTP.P('<H1>社員登録</H1>');
 30     HTP.P('<HR>');
 31     HTP.P('<FORM ACTION="emp2_update_exe" METHOD="POST">');
 32     HTP.P('<TABLE BORDER>');
 33   -- 社員番号は主キーなので表示のみで更新対象外とした(パラメータも値もなし)
 34     HTP.P('<TR><TD BGCOLOR="SILVER">社員番号</TD>' ||
 35               '<TD><FONT COLOR="GRAY">' ||TO_CHAR(REC.EMPNO) ||'</FONT></TD></TR>');
 36   /*******************************************/
 37   /*-社員名をセット--------------------------*/
 38   /*******************************************/
 39     HTP.P('<TR><TD BGCOLOR="SILVER">社員名</TD>' ||
 40     '<TD><INPUT TYPE="TEXT" NAME="P_ENAME" VALUE="' ||REC.ENAME ||'"></TD></TR>');
 41   /*******************************************/
 42   /*-入社日をセット--------------------------*/
 43   /*******************************************/
 44     HTP.P('<TR><TD BGCOLOR="SILVER">入社日(YYMMDD)</TD>''
 45          <TD><INPUT TYPE="TEXT" NAME="P_HIREDATE" VALUE="' ||
 46                           TO_CHAR(REC.HIREDATE,'YYMMDD') ||'">' ||'</TD></TR>');
 47   /*****************************************************************/
 48   /*-部門番号は上記のリスト(V_DEPT)で該当の値がSELECTEDになっている*/
 49   /*****************************************************************/
 50     HTP.P('<TR><TD BGCOLOR="SILVER">部門</TD><TD>' ||V_DEPT ||'</TD></TR>');
 51   /***********************************************/
 52   /*-TEXTエリアタグで囲まれた範囲がセットされた値*/
 53   /***********************************************/
 54     HTP.P('<TR><TD BGCOLOR="SILVER" COLSPAN="2">備考</TD></TR>');
 55     HTP.P('<TR><TD COLSPAN="2"><TEXTAREA NAME="P_NOTE" rows="10" cols="70">' ||
 56                                REC.NOTE ||
 57                               '</TEXTAREA></TD><TR>');
 58     HTP.P('</TABLE>');
 59   /*******************************************************************/
 60   /*-社員番号は更新処理で必要なので、非表示のパラメータとして送信する*/
 61   /*******************************************************************/
 62     HTP.P('<INPUT TYPE="HIDDEN" NAME="P_EMPNO" VALUE="' ||P_EMPNO ||'">');
 63     HTP.P('<INPUT TYPE="SUBMIT" VALUE="送信">');
 64     HTP.P('</FORM>');
 65     HTP.P('</BODY>');
 66     HTP.P('</HTML>');
 67*  END EMP2_UPDATE_FORM;
SQL> /

プロシージャが作成されました。

簡単に解説いたします。

まず19行目で、SELECT ~INTO文で、対象となる行レコードを変数(REC)に取得します。そして、このREC変数の各フィールドの値を以下の各タグに反映させています。

この中でわかりにくいのが 23-24行目の部門リストの処理だと思います。
これは、10~15行目で生成した部門リストの該当する値のOPTIONタグを選択した状態(SELECTED)としているものです。

11~15行目で生成された部門リストは、初めはどのOPTIONタグもSELECTEDの指定がありません。ですからこのままでは、最初のOPTIONタグが選択された状態となります。
そこで該当する部門番号のOPTIONタグをSELECTED状態としなければならないわけです。

そして23-24行目がその記述ですが、少しわかりにくいと思うのでその考え方をわかりやすく説明します。

例えば仮に、該当の部門番号が20だとすると、以下のように部門リスト内のOPTIONタグを変更しなければなりません。

変更前
<OPTION VALUE="20">
変更後
<OPTION VALUE="20" SELECTED>

つまり、この変更は「VALUE="20"」という文字列部分を「VALUE="20" SELECTED」という文字列に置き換えると考えてもいいわけですね。

そこで、以下のように記述すれば、V_DEPTNに格納された選択リストの部門20の項目が選択された状態となります。

V_DEPTNO := REPLACE(V_DEPTNO,'VALUE="20"','VALUE="20" SELいかECTED');

しかし、"20"という値は固定値ですから、このままの記述ではいけません。この部門番号"20"を実際に取得した部門番号(変数(REC.DEPTNO)で記述すればどのような部門番号でもOKです。そのためには、文字列連結の細かいコーディングをする必要がありますが、以下のように考えれば間違いなく正しく文字列連結が可能です。
『バックナンバー第93回  文字列連結プログラミングのコツ』参照)

まず、文字列のなかで、"20"という文字列を周りの文字列から分離します。
例えば以下のようにです。区切り文字(シングルコーテーション)と連結文字(||)に注目してください。

(例)
(分離前) 'VALUE="20"'

(分離後) 'VALUE="' || '20' || '"'

このようにすればどんな文字列でも、正しく周りから切り離すことができますね。そしてこの切り離された文字列 '20'の部分をREC.DEPTNO変数に置き換えます。NUMBER型なので、TO_CHARで文字列に変換して、置き換えます。


'VALUE="' || TO_CHAR(REC.DEPTNO) || '"'

ということで、先ほどのREPLACE文は以下のようになります。

V_DEPT := REPLACE(V_DEPT,'VALUE="' ||TO_CHAR(REC.DEPTNO) ||'"',
                         'VALUE="' ||TO_CHAR(REC.DEPTNO) ||'" SELECTED');

これがソースコード 23-24行目の意味です。

これで、該当する部門番号(REC.DEPTNO)の部門リストのOPTIONタグをSELECTEDの状態にできます。

選択リストの該当値をSELECTEDにする方法としてはこれ以外の方法もあり得えますが、私はこのREPLACE方式が一番簡単だと思います。
選択リストの生成処理は、登録処理(第107回のEMP2_INSERT_FORMプロシージャ)にもありますから、登録処理のロジックにREPLACE処理を加えるだけで簡単に対応できるわけです。

ということで選択リストについてはこのように対応していただければよいと思います。

次にそれ以外の各項目に読み込んだ値をセットする方法ですが、前述したように、TYPE="TEXT"のINPUTタグ(<INPUT TYPE="TEXT"・・・>)の場合は、VALUE属性でその値を指定します。例えば、社員名(40行目)、入社日(45行目)をそれぞれ、VALUE属性に変数の値をセット(文字列連結)していることがわかります。
また、入力項目が複数行の場合、TEXTAREAタグを用いますが、その場合の値のセットの仕方は、単に、TEXTAREAタグの開始タグ(<TEXTAREA・・・>)と終了タグ(</TEXTAREA>)の間にセット(文字列連結)するだけです。(56行目)
このようにとても簡単ですね。

また、注意点としては、社員番号が主キーであることから今回は表示のみで更新対象外としました。35行目をみると、単に社員番号 REC.EMPNOをTO_CHAR関数で文字列に変換して文字列連結しているだけです。
つまり、INPUTタグなどではなく(入力領域でなく)単に表示しているだけです。

しかし、データ更新処理(31行目のemp2_update_exeプロシージャ 現時点ではまだ未作成)では、該当する社員の社員番号が必要です。
そこで、非表示の隠しパラメータとして社員番号を持たせています。(62行目)  
TYPE="HIDDEN"のINPUTタグは、表面的には非表示で見えませんが、いわゆる隠し項目としてパラメータ名と値を持っているわけです。

では、解説はここまでにして、実際にこの更新処理のフォーム画面を生成するプロシージャをWEBブラウザから実行してみましょう。

前回、登録した新規の社員(社員番号 7938 鈴木一郎さん)を早速、更新処理のフォーム画面に読み込みます。

バックナンバー『第103回「WEBアプリ作成(1) (Oracle DBとPL/SQLだけで、即、WEBアプリ)」』の設定どおりであれば、以下のURLです。

http://localhost:8080/dad/emp2_update_form?p_empno=7938

そうすると、以下の画面となります。

ご覧のように、画面が開いたときから該当社員のデータが読み込まれていることがわかりますね。
もちろん各項目とも、値の更新は可能なわけです。

そして、送信ボタンをクリックすると、・・・

送信先の emp2_update_exeプロシージャが現段階ではまだ作成されていないので、予定通りエラーとなります。
このプロシージャは次回、完成させましょう。

いかがですか? 
データ登録(INSERT)と違って、データ更新(UPDATE)の場合は、読み込んだ該当レコードの値を各項目にセットする必要があります。
それはまとめると以下の通りです。

【入力テキスト項目の場合】
<INPUT  TYPE="TEXT" NAME="パラメータ名" VALUE="値">

【複数行のテキスト項目の場合】
<TEXTAREA NAME="パラメータ名" ・・・></TEXTAREA>

【選択リストの場合】
<SELECT NAME="パラメータ名">・・</OPTION VALUE="値" SELECTED>表示文字列</OPTION>・・</SELECT>

今回はここまでです。
次回もご期待ください。

先頭へ戻る