2022年3月25日金曜日

PL/SQL APIのAPEX_ITEMを使う

 Oracle APEXのPL/SQL APIとしてパッケージAPEX_ITEMが提供されています。APIのマニュアルを参照すると、APEX_ITEM (Legacy)となっており、また、以下のように記載されています。

This API is designated as legacy.

You can use the APEX_ITEM package to create form elements dynamically based on a SQL query instead of creating individual items page by page.
そのため、使ってはいけない気になります。しかし、Legacyだといっているだけで、サポートをやめているわけではありません。保証はできませんが、Oracle APEXのPL/SQL APIの動作はオラクル・データベースに依存しているので、オラクル・データベース自体の仕様変更がない限りは、PL/SQL APIがデサポートになるというのはあまり考えられません。そして、過去に動いていたSQLやPL/SQLが動かなくなるような仕様変更は、(不具合でもない限り)あまり聞いたことがありません。

Oracle APEXであれば、例えばTabular FormはLegacyとなっています。マニュアルには以下の注意書きがあります。APEX_ITEMはここまで強く書かれていません。
Note: A tabular form is a legacy application component. Although existing legacy tabular forms are supported, the creation of new legacy tabular forms has been desupported. Oracle recommends developers create interactive grids instead.
対話グリッドの利用が推奨ですが、すでに作られているものについてはサポートを継続すると記載されています。この他にもJavaScript APIに含まれるNon-namespace APIsもJavaScriptが一般的に使われるようになる前に開発したもので、推奨はNamespaceがあるAPIです。しかし、サポートをやめるという話はありません。

Oracle Multimediaのように無くなる機能はあるので100%大丈夫ということはありませんが、開発チームには「きちんと代替できる機能が提供されるまでは、既存の機能を除くことはない。」という方針があるようです。

さて、現在提供されているコンポーネントでは代替できない実装として、クラシック・レポートとAPEX_ITEMを組み合わせた更新可能なレポートがあります。以下のようなアプリケーションになります。


実装方法について、以下より簡単に紹介します。

サンプル・データセットのEMP/DEPTに含まれる表EMPを使います。

SQLワークショップユーティリティサンプル・データセットを開き、EMP/DEPTインストールします。アプリケーションの作成は不要です。


アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前更新可能レポートとします。

アプリケーションの作成を実行します。


アプリケーションが作成されたら、ページ・デザイナにてホーム・ページを開きます。

Content Bodyにリージョンを作成します。

識別名前従業員とします。タイプとしてクラシック・レポートを選択します。ソースタイプとしてSQL問合せを選択し、SQL問合せとして以下を入力します。

select
apex_item.text(
p_idx => 1
, p_attributes => 'class="apex_disabled"'
, p_value => empno
) empno
, ename
, apex_item.select_list_from_query(
p_idx => 2
, p_value => job
, p_query => 'select distinct job d, job r from emp'
, p_show_extra => 'NO'
, p_item_label => 'JOB'
) JOB
, apex_item.select_list_from_query(
p_idx => 3
, p_value => mgr
, p_query => 'select ename d, empno r from emp'
, p_null_value => ''
, p_null_text => 'マネージャーなし'
, p_show_extra => 'NO'
, p_item_label => 'MGR'
) MGR
, apex_item.date_popup2(
p_idx => 4
, p_value => hiredate
, p_item_label => 'HIREDATE'
) HIREDATE
, apex_item.text(
p_idx => 5
, p_value => to_char(sal)
, p_size => 8
, p_item_label => 'SAL'
) sal
, apex_item.text(
p_idx => 6
, p_value => to_char(comm)
, p_size => 8
, p_item_label => 'COMM'
) comm
, apex_item.select_list_from_query(
p_idx => 7
, p_value => deptno
, p_query => 'select dname d, deptno r from dept'
, p_show_extra => 'NO'
, p_item_label => 'DEPTNO'
) DEPTNO
from EMP

プロシージャAPEX_ITEM.TEXTなどを呼び出し、クラシック・レポートの列としてアイテムを生成し、更新可能にしています。


APEX_ITEMを使って生成した列をすべて選択し、セキュリティ特殊文字をエスケープOFFにします。APEX_ITEMによりアイテムの形式は変わりますが、識別タイプはすべてプレーン・テキストです。


ページを実行すると、以下のようになります。


更新処理を組み込みます。

レポートのリージョン従業員に送信ボタンを作成します。

識別ボタン名B_SUBMITラベル送信とします。動作アクションはデフォルトのページの送信とします。


左ペインでプロセス・ビューを開き、実際のデータベースの更新処理をプロセスとして実装します。

プロセスを作成します。

識別名前従業員の更新とします。タイプコードを実行です。ソースPL/SQLコードとして以下を記述します。

declare
l_count number;
begin
l_count := apex_application.g_f01.count;
apex_debug.info('Total ' || l_count || ' rows accepted.');
for i in 1..l_count
loop
update emp
set
job = apex_application.g_f02(i)
, mgr = apex_application.g_f03(i)
, hiredate = apex_application.g_f04(i)
, sal = apex_application.g_f05(i)
, comm = apex_application.g_f06(i)
, deptno = apex_application.g_f07(i)
where
empno = apex_application.g_f01(i);
end loop;
end;

レポートに指定した値は、APEX_APPLICATION.G_Fxxに配列として送信されます。xxの数値はAPEX_ITEMの呼び出しで、引数p_idxとして指定した数値になります。

サーバー側の条件として、ボタン押下時B_SUBMITを選択します。


以上でアプリケーションは完成です。

対話グリッドとは異なり、画面に表示されている行だけが更新の対象になります。ページ送りには対応していません。

例えば、レイアウト行数に変更します。


クラシック・レポートには、最大5行が表示されます。送信ボタンを押したときに更新されるのは、その時点で表示されている5行だけです。


機能的には対話グリッドの方が豊富ですが、クラシック・レポートによる更新フォームは見かけを変更する自由度が高いです。

例として、クラシック・レポートの外観テンプレートValue Attribute Pairs - Columnに変更してみます。


縦方向に列が表示されますが、更新可能レポートとしての動作は変わりません。(画面を見やすくするために行数を2に変更しています。)


クラシック・レポートのテンプレートをカスタマイズすることにより、より特別な見た目の更新可能なレポートを作成することができます。

今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/updatable-classic-report.sql

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