2021年4月22日木曜日

Excelファイルのアップロード - その2 - ユーザーの表を使う方法

 こちらの記事の続きです。同じページを表APEX_APPLICATION_TEMP_FILESではなく、自分で作成した表を使って実装します。

アップロードしたExcelファイルを保存する表を作成します。クイックSQLの以下のモデルから表FUP_FILESを作成します。

# prefix: fup
# semantics: default
files
content file

生成されるDDLは以下になります。生成したDDLを実行し、表を作成します。

create table fup_files (
id number generated by default on null as identity
constraint fup_files_id_pk primary key,
content blob,
content_filename varchar2(512),
content_mimetype varchar2(512),
content_charset varchar2(512),
content_lastupd date
)
;

すでに作成済みのアプリケーション、ファイルのアップロードにページを追加します。アプリケーション・ビルダーよりページの作成を実行し、ページ作成ウィザードフォームをクリックします。

フォームをクリックします。

ページ名ユーザー表とします。ページ・モード標準送信時にここにブランチ取り消してページに移動の双方とも、自ページのページ番号(この場合は3)を指定します。に進みます。

ナビゲーションのプリファレンスとして、新規ナビゲーション・メニュー・エントリの作成を選択します。に進みます。

データ・ソースローカル・データベースとし、表/ビューの名前FUP_FILES(表)を選択します。に進みます。

主キー型主キー列の選択とし、主キー列としてID(Number)を選びます。作成をクリックします。


ページが作成されます。最初にP3_CONTENT_MIMETYPEP3_CONTENT_CHARSETP3_CONTENT_LASTUPDを表示させないため、これらのページ・アイテムを選択して、サーバー側の条件なしに変更します。


ファイル参照のページ・アイテムP3_CONTENTを選択し、前の記事のP2_FILEと同様の動作になる設定を行なっていきます。

ラベルアップロードするファイル設定表示形式Block Dropzoneドロップ・ゾーンの説明Excelファイル(XLSX形式)をドロップしてください。とします。記憶域タイプBLOB column specified in Item Source attributeとします。MIMEタイプ列CONTENT_MIMETYPEファイル名列CONTENT_FILENAME文字セット列CONTENT_CHARSETBLOB最終更新列CONTENT_LASTUPDを指定します。最大ファイル・サイズ5000KBとします。


一旦ファイルが選択されたら、その後にページ・アイテムが変更されることを防ぐため、サーバー側の条件タイプアイテムがNULLを選択し、アイテムにP3_CONTENTを指定します。この設定によりファイルが未選択のときに限り、ファイル参照が表示されます。


主キーであるページ・アイテムP3_IDを、ページ送信後に設定されたIDの値を維持するよう、セッション・ステートの保持セッションごと(ディスク)に変更します。


ファイルを選択した時点でアップロードを行うよう、ページ・アイテムP3_CONTENT動的アクションの作成を行います。

動的アクションの名前ファイルのアップロードとします。タイミングはデフォルトでイベント変更選択タイプアイテムアイテムP3_CONTENTとなり、P3_CONTENTが変更されるとアクションが実行されます。


Trueアクションを選択し、アクションとしてページの送信を選択します。設定リクエスト/ボタン名としてCREATEを入力します。この指定により、動的アクションから実行されるページの送信で、ボタンCREATE(ラベルは作成)を押した時と同じ動作、つまり表へのデータの挿入が行われます。


この時点でファイルのアップロードまでは実装できています。

アップロードされた結果をプレビューするために、クラシック・レポートのリージョンを作成します。

リージョンを作成し、名前プレビュータイプクラシック・レポートとします。ソース位置ローカル・データベースタイプSQL問合せとし、SQL問合せに以下のSELECT文を記載します。

select
col001 "PREFECTURE",
col002 "CITY",
col003 "COUNT"
from
apex_data_parser.parse(
p_content =>
(
select content from fup_files
where id = :P3_ID
),
p_file_name => :P3_CONTENT_FILENAME,
p_skip_rows => 1,
p_file_charset => 'AL32UTF8',
p_max_rows => 10
)


ページ作成ウィザードによって生成されたボタンはすべて使用しないので、ボタンCANCELDELETESAVECREATEを選択し、サーバー側の条件タイプなしにします。


表FUD_CITYLISTにデータを投入するプロセスを作成します。データの送信を行うボタンを作成します。ボタン名B_SUBMITラベル送信とします。


続いて、ボタンB_SUBMITが押された時に実行されるプロセスを作成します。名前表にロードとし、タイプコードを実行ソースの位置ローカル・データベース言語PL/SQLを選択し、PL/SQLコードとして以下を記述します(プレビューではないのでp_max_rowsの指定を除いています)。サーバー側の条件として、ボタン押下時B_SUBMITを指定することにより、送信ボタンを押した時のみ実行されるようにします。

begin
delete from fup_citylist;
insert into fup_citylist(prefecture, city, count)
select
col001 "PREFECTURE",
col002 "CITY",
col003 "COUNT"
from
apex_data_parser.parse(
p_content =>
(
select content from fup_files
where id = :P3_ID
),
p_file_name => :P3_CONTENT_FILENAME,
p_skip_rows => 1,
p_file_charset => 'AL32UTF8'
);
end;


上記のコードは、送信をクリックした際に、すでに保存されているデータをすべて削除し、新たにアップロードしたデータで入れ替えています。追加やマージといった動作にしたい場合は、PL/SQLのコードを変更することになります。

以上で表へのデータのロードも実行されるようになりました。動作確認をもう少し簡単にするため、ページを初期化するボタンと表FUD_CITYLISTの内容を表示するレポートを追加します。この作業は前の記事とまったく同じです。

ボタンの作成を行い、ボタン名B_CLEARラベルクリアとします。


ボタンB_CLEARを押した時に実行されるプロセスを作成します。作成したプロセスの名前ページの初期化とし、タイプセッション・ステートのクリアを選択します。サーバー側の条件として、ボタン押下時B_CLEARを選択します。これでクリアのボタンを押した時に、ページが初期化されます。


アップロード結果を表示するクラシック・レポートを作成します。新規にリージョンの作成を行います。

名前アップロード結果とし、タイプクラシック・レポートを選択します。ソース表名FUP_CITYLISTを選択し、プレビューと横並びになるよう、レイアウト新規行の開始OFFとします。


以上で完成です。ページを実行し、実装を確認します。以下の動作になります。


ユーザーが作成した表にアップロードしたファイルを保存しているので、不要になったデータを削除する処理を実装する必要があります。共有コンポーネントアプリケーション・ロジックに含まれる自動化を、そのような用途に使うことができます。


以上でデータ・ロードに関する説明は終了です。

Oracle APEX 21.1では、これらの作業のほとんどがページ作成ウィザードによって行われる予定です。ですので、いちからページを作成することはありませんが、自動的に生成されたコンポーネントをカスタマイズする際には、役に立つ知識かと思います。

作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/excelfileupload.sql
サンプルのデータはこちらです。
https://github.com/ujnak/apexapps/blob/master/exports/citylist.xlsx

Oracle APEXのアプリケーション作成の参考になれば幸いです。