2022年12月16日金曜日

カスケードLOVのソース定義について

 2つのページ・アイテムがあり、それぞれタイプがシャトルとなっています。このページ・アイテムには親子関係があり、親となるシャトルで選択した値に基づき、子のシャトルで選択できる値が決まります。

サンプル・データセットのEMP/DEPTをデータ・ソースとして使い、以下のようなページを作成します。



基本の実装



親のシャトルがP1_DEPTNOとして作成されています。表DEPTからDEPTNOを複数選択します。

LOVSQL問合せは以下になります。

select dname d, deptno r from dept


従業員を選択する子であるシャトルはP1_EMPNOとして作成されています。

LOVSQL問合せは以下になります。カスケードLOV親アイテムとしてP1_DEPTNOを指定します。親アイテムとして指定したアイテムは必ず送信されるため、送信されるアイテムに指定する必要はありません。

ページ・アイテムに複数の値が設定される場合、それぞれの値は':'(コロン)で区切られます。そのため、P1_DEPTNOの値をapex_string.splitを呼び出して分割しています。

ページ・アイテムP1_DEPTNOのシャトルで選択した部門の従業員に限り、P1_EMPNOのシャトルで選択できるようになります。


ここまでが基本の実装です。


SQLを記述できない場合



従業員の表がそれぞれ部門で分割されているケースを想定します。

create table emp_accounting as select * from emp where deptno = 10;
create table emp_research as select * from emp where deptno = 20;
create table emp_sales as select * from emp where deptno = 30;
create table emp_operations as select * from emp where deptno = 40;


部門ごとに4つの表が作られています。EMP_ACCOUNTINGEMP_RESEARCHEMP_SALESEMP_OPERATIONSです。親となるシャトルではこれらの表を選択し、子となるシャトルは選択された表から従業員を選択します。

親のシャトルのSQL問合せは以下に変わります。

select dname d, 'EMP_' || dname r from dept

ページ・アイテムP3_DEPTNOはコロンで区切られた表名を複数持ちます。


子のシャトルでは、LOVタイプSQL問合せを返すファンクション本体に変更し、SQL問合せを戻すPL/SQLファンクション本体として以下を記述します。ファンクションの評価時はページ・アイテムP3_DEPTNOはnullになります。評価に失敗するため、0行を返すダミーのSELECT文を戻しています。

カスケードLOVは基本と同じ設定になります。



動的にSELECT文を作成できない場合



動的にSQLを作る場合でも、最終的には実行可能なSELECT文が生成される必要があります。SELECT文を作るのが困難なケース(RESTサービスを呼び出すなど)では、パイプライン表関数を作成することで対応できる場合もあります。

今回の例を実装すると、以下のようになります。

作成したパイプライン表関数get_cascade_lov_sourceを使用したSQL問合せは以下になります。

select display_value, return_value from table(get_cascade_lov_source(:P2_DEPTNO))

パイプライン表関数による実装の場合、表示値と戻り値を返せばよいので実際のデータ・ソースが表である必要はありません。



カスケードLOVの親アイテムを指定できない場合



あまり無いとは思いますが、カスケードLOVの親アイテムを設定できない場合を考えてみます。

この場合、親となるページ・アイテムが変更されたときに、子となるページ・アイテムをリフレッシュする必要があります。


ページ・アイテムの変更イベントでページ・アイテムのリフレッシュを実行します。このTRUEアクションは、一般的なリフレッシュの設定です。


子アイテムのLOVSQL問合せ、または、ファンクション本体に親アイテムであるページ・アイテムがバインド変数として使用されている場合、カスケードLOVの親アイテムを指定せずに、送信するページ・アイテムを指定する方法はありません

このため、親となるページ・アイテムのセッション・ステートストレージセッションごと(永続)に切り替えます。


TRUEアクションを作成し、子であるページ・アイテムをリフレッシュする前に配置します。

アクションサーバー側のコードを実行を選択します。PL/SQLコードは不要なのでnull;とします。送信するアイテムとして親となるページ・アイテムを指定します。

セッション・ステートの定義はセッション(永続)になっているため、送信されたページ・アイテムの値はデータベースに保存されます。子アイテムのソースとなるコードが実行される際に、サーバーに保存されている値がバインド変数に割り当てられるため、親アイテムの値が反映された結果が得られます。


今回の記事は以上です。

検証に使用したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/cascade-shuttle-lov-source.zip

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