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

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

第107回「WEBアプリ作成(5)(データ登録 1/2)」

2014.10.16

こんにちは。インストラクターの蓑島です。
前回までは、データの問い合わせ(SELECT)でしたが、今回と次回でデータ登録(INSERT)を行うWEBアプリケーションについて解説してきます。

データ登録を行うためには、データを入力するフォーム画面とそのデータを使って実際にデータ登録を行う処理が必要です。これらの『入力フォーム画面』と、『データ登録処理』の両方をそれぞれ別のプロシージャで行います。

では、EMP表(社員表)を例に解説します。
使用する列を限定することと、CLOB型の列を設けたいので、EMP2という名前で別の表を作成します。

SQL> SHOW USER
ユーザーは"SCOTT"です。

-- EMP表の特定例をもとに、EMP2表を作成します。(SELECTの結果でデータも格納されます)
SQL> CREATE TABLE EMP2 AS SELECT EMPNO, ENAME, HIREDATE, DEPTNO FROM EMP;

表が作成されました。

-- EMP2表にCLOB型のNOTE(備考)という名前の列を追加します。
SQL> ALTER TABLE EMP2 ADD (NOTE CLOB);

-- EMP2表のEMPNO列に主キーを設定します。
SQL> ALTER TABLE EMP2 ADD CONSTRAINT PK_EMP2 PRIMARY KEY(EMPNO);

表が変更されました。

-- EMP2表のDEPTNO列(部門番号)にDEPT表を参照する外部キー制約を設定します。
SQL> ALTER TABLE EMP2 ADD CONSTRAINT FK_EMP2_DEPT
2 FOREIGN KEY(DEPTNO) REFERENCES DEPT(DEPTNO);

表が変更されました。

EMP2表は以下のような列定義です。
SQL> DESC EMP2
名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 EMPNO                                     NOT NULL NUMBER(4)         -- 社員番号(数値型)(主キー)
 ENAME                                              VARCHAR2(10)      -- 社員名(文字型)
 HIREDATE                                           DATE              -- 入社日(日付型)
 DEPTNO                                             NUMBER(2)         -- 部門番号(外部キー)
 NOTE                                               CLOB              -- 備考(CLOB型)

このEMP2表(社員表)にデータ登録するための入力フォーム画面を生成するプロシージャの例を以下に用意しました。
プロシージャの名前を EMP2_INSERT_FORM としました。

SQL> create or replace
  2  PROCEDURE EMP2_INSERT_FORM
  3  IS
  4    V_DEPT  VARCHAR2(1000);
  5  BEGIN
  6  -- 部門のリストを作成する
  7    V_DEPT  := '<SELECT NAME="P_DEPTNO"><OPTION VALUE="NULL">-</OPTION>';   -- リストの最初の項目はNULL値とする
  8    FOR REC IN (SELECT * FROM DEPT ORDER BY DEPTNO) LOOP
  9        V_DEPT := V_DEPT || '<OPTION VALUE="' ||TO_CHAR(REC.DEPTNO) ||'">' ||REC.DNAME ||'</OPTION>';
 10    END LOOP;
 11    V_DEPT := V_DEPT || '</SELECT>';
 12  -- ここから画面表示処理
 13    HTP.P('<HTML>');
 14    HTP.P('<HEAD><TITLE>社員登録</TITLE></HEAD>');
 15    HTP.P('<BODY>');
 16    HTP.P('<H1>社員登録</H1>');
 17    HTP.P('<HR>');
 18    HTP.P('<FORM ACTION="emp2_insert_exe" METHOD="POST">');
 19    HTP.P('<TABLE BORDER>');
 20    HTP.P('<TR><TD BGCOLOR="SILVER">社員番号</TD><TD><FONT COLOR="GRAY">自動生成</FONT></TD></TR>');
 21    HTP.P('<TR><TD BGCOLOR="SILVER">社員名</TD><TD><INPUT TYPE="TEXT" NAME="P_ENAME"></TD></TR>');
 22    HTP.P('<TR><TD BGCOLOR="SILVER">入社日(YYMMDD)</TD><TD><INPUT TYPE="TEXT" NAME="P_HIREDATE"></TD></TR>');
 23    HTP.P('<TR><TD BGCOLOR="SILVER">部門</TD><TD>' ||V_DEPT ||'</TD></TR>');
 24    HTP.P('<TR><TD BGCOLOR="SILVER" COLSPAN="2">備考</TD></TR>');
 25    HTP.P('<TR><TD COLSPAN="2"><TEXTAREA NAME="P_NOTE" rows="10" cols="70"></TEXTAREA></TD><TR>');
 26    HTP.P('</TABLE>');
 27    HTP.P('<INPUT TYPE="SUBMIT" VALUE="送信">');
 28    HTP.P('</FORM>');
 29    HTP.P('</BODY>');
 30    HTP.P('</HTML>');
 31  END EMP2_INSERT_FORM;
 32  /

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

SQL>

では実際にこのEMP2_INSERT_FORMプロシジャーをブラウザからリクエストします。
バックナンバー 第103回「WEBアプリ作成(1) (Oracle DBとPL/SQLだけで、即、WEBアプリ)」の設定であれば、以下のURLです。

http://localhost:8080/dad/emp2_insert_form

そうすると、ログインが求められますので、このプロシージャの所有者であるSCOTTユーザとそのパスワードでログインします。
1
そうすると、以下のような空の入力フォーム画面が表示されます。
2
そしてこの入力フォームに対して、実際に入力したイメージが以下の画像です。
3
ではこれを見ながら、上記のソースコードについても解説します。

まず、社員番号の部分ですが、社員番号(EMPNO列)は社員表(EMP2表)の主キーなので、キーボードから手入力することは通常はありません。
そこで「自動生成」という表示のみを行っています。(ソースコード 20行目)
実際に社員番号を生成するのは、リクエストの送信先のプロシージャの中で行います。

また社員名については、入力のテキストボックス(<INPUT TYPE="TEXT" ・・・・>)に「P_ENAME」というリクエストパラメータ名を付けています。(21行目)
同様に、入社日については、「P_HIREDATE」というリクエストパラメータ名を付けています。

注目していただきたいのは、部門の部分です。
EMP2表の部門番号(DEPTNO列)は、DEPT表(部門表)の部門番号(DEPTNO列)を参照する外部キー制約が設定されています。このような場合、部門番号を直接手入力するのではなく、選択リストから部門名を選択することで部門番号が設定される方法が一般的です。そこでリストを作成し、そのリストを入力フォームの部門の部分にはめ込みます。

部門のリストは、V_DEPTという変数に格納します。(4行目で宣言) 
そして実行部の7行目~11行目で作成しています。HTMLで、選択リストは以下の構文の文字列なので、それに合わせて生成します。

選択リストの構文
      <SELECT NAME="名前"><OPTION VALUE="値">リスト要素の表示</OPTION><OPTION VALUE="値>・・</OPTION></SELECT>

つまり最初にSELECTタグ( <SELECT・・・> )があり、次にリストの要素であるOPTIONタグのセット( <OPTION>~</OPTION> )があり、最後にSELECTの終了タグ( </SELECT>)があります。

まず、7行目で、V_DEPT変数にSELECTタグと、最初のOPTIONタグのセットを格納しています。
SELECTタグで指定した名前は P_DEPTNOです。
つまりP_DEPTNOというリクエストパラメータで、部門番号が送信先プロシージャに送信される予定です。

そして同じく7行目で最初のOPTIONタグのセットを記述しています。
つまり、このリストの最初の値は'NULL'ですが、表面上のリストの表示は、ハイフン( - )です。

次に8~10行目で、カーソルFORループ文で、 (SELECT * FROM DEPT ORDER BY DEPTNO)のSELECT文からDEPT表の1行1行を取り出して、V_DEPT変数の後ろにオプションタグのセットを追加します。
例えば、部門番号20の部門名がRRESEARCHだとすると、以下のようなオプションタブのセットになります。

'<OPTION VALUE="20">RESEARCH</OPTION>'

そこで、この中の可変の部分つまり、20 と、RESEARCHを回りの文字列から分離します。
(バックナンバー第93回「文字列連結プログラミングのコツ」を参照してください)

'<OPTION VALUE="' || '20' || '">' ||'RESEARCH' ||'</OPTION>'

ダブルコーテーション(")やシングコーテーション(')が連続してわかりにくいですが、コツをつかめば簡単に間違えることなく確実に記述できます。

そこでこの分離した動的な文字列の部分つまり、'20'と、'RESEARCH'をカーソルFORループで取得した行(REC変数)を使って、それぞれREC.DEPTNO および、REC.DNAMEに置き換えます。ただし、REC.DEPTNOは数値(NUMBER型)なので、文字型に変換しなければいけません。
したがって、TO_CHAR(REC.DEPTNO)とします。
これらのレコード変数を使った値を、'20'と'RESEARCH'の部分に置き換えれば、以下の記述となるわけです。

'<OPTION VALUE="' ||TO_CHAR(REC.DEPTNO) ||'">' ||REC.DNAME ||'</OPTION>'  -- ソースコード 9行目の記述参照

これをカーソルFORループ文で、部門表の1行1行ついて、オプションタグのセットとしてリストに追加します。
そしてループが終わって、最後にSELECTの終了タグ( </SELECT> )を付けます。(11行目)

これで選択リストは完了です。
例えば入力フォームを実際に表示してブラウザを右ボタンクリックでソースを表示すれば、選択リストの部分のソースは以下のようになっていると思います。

<SELECT NAME="P_DEPTNO"><OPTION VALUE="NULL">-</OPTION><OPTION VALUE="10">ACCOUNTING</OPTION><OPTION VALUE="20">RESEARCH</OPTION><OPTION VALUE="30">SALES</OPTION><OPTION VALUE="40">OPERATIONS</OPTION></SELECT>

これをみてわかるように、選択リストから、「RESEARCH」を選択すると、その値は「20」となるわけです。

このようにして完成した部門のリスト(V_DEPT)を入力フォームの所定のセル(<TD>~</TD>) に連結しています。(23行目)

次に備考ですが、備考はCLOB型であり、大量の文字データを格納できます。
そこで、複数行にわたる大量の文字データを格納するためには、普通のテキストボックスではなく、テキストエリアというものを使用します。
テキストエリアの構文は以下の通りです。

テキストエリアの構文
    <TEXTAREA  NAME="名前" ROWS="縦幅" COLS="横幅"></TEXTAREA>

ソースコード25行目を見ると、テキストエリアの名前は、P_MSG です。
つまり、ここに入力した大量の文字データがP_MSGというリクエストパラメータ名で送信先に送信されます。また、テキストエリアには必ず、終了タグ( </TEXTAREA> ) が必要であることに注意してください。
例えばテキストボックス( <INPUT TYPE="TEXT">) には終了タグはありませんが、テキストエリアには終了タグが必要です。

そして、フォームの最後に送信ボタンです。送信ボタンをクリックすれば、フォーム内のリクエストパラメータは送信先に送信されます。なお送信先は、FORMタグのACTION属性に指定されます。(18行目)

<FORM ACTION="emp2_insert_exe" METHOD="POST">

ACTION属性はリクエストパラメータの送信先ですが、emp2_insert_exeという送信先(プロシージャ)が現時点で作成されていないので、エラーになります。
4
また、FORMタグの属性に METHOD="POST" という記述があります。
これを指定すると、リクエストパラメータはURLとは別に送信されますので、URLの後ろにリクエストパラメータが付加されません。
上記のイメージにあるとおり、URLの後ろにリクエストパラメータが付加されていないことがわかります。この属性を省略すると、METHOD="GET" という指定となり、リクエストパラメータはURLの後ろに付加されて送信されます。前回まではすべてこの属性を省略したFORMタグでした。

大量データを送信する場合は、もちろん、METHOD="POST"の方が望ましいです。ですが、私は開発段階ではあえて、METHOD="GET"にすることがよくあります。
というのは、そうすることで、実際にどのようなパラメータ名でどのような値が送信されているか、URLを見て簡単に判断できるからです。そうすれば実際にそれを受信プロシージャ側のパラメター名と、すべて一致するかどうかチェックするといったことが簡単にできます。

では今回はここまでです。
次回はこの続きで、送信先のEMP2_INSERT_EXEプロシージャを実際に作成して、データ登録処理を完成させましょう。

ご期待ください。

先頭へ戻る