2022年5月12日木曜日

APEXコレクションの値を表関数で使うためにCROSS APPLYを使用する

 表関数を実装するとAPI呼び出しの結果をSELECT文で扱うことができます。SQLのCROSS APPLYを使うと、APEXコレクションなどに保存した値を表関数に与えることができます。

少し前に、Oracle Spatialの接触追跡を使うAPEXアプリケーションを作成しました(こちらの記事)。この記事では(問題があったため)接触追跡はRESTサービスとして実装しています。その後、表関数でも接触追跡(SDO_OBJ_TRACING.GET_ALL_DURATIONSの呼び出し)が出来たので、その実装方法を紹介しています。(こちらの記事)。

この接触追跡の表関数を使って、CROSS APPLYの使い方を紹介します。

接触追跡を行う対象をAPEXコレクションCONTACT_USERSに保存します。APEXコレクションへの値の挿入、変更、削除には、対話グリッドを利用します。

作成したアプリケーションは以下のように動作します。

元記事で作成しているREST APIを使ったAPEXアプリケーションを改変します。表関数contact_tracingが作成済みであることを前提とします。


APEXコレクションの初期化


接触追跡の条件を保存するAPEXコレクションを初期化します。使用するAPEXコレクションの名前はCONTACT_USERSとします。これから対話グリッドのソースやマップのレイヤーのソース、その他のコードにもAPEXコレクション名を指定する箇所があるので、直書きを避けるためにアプリケーション定義の置換として、置換文字列を設定します。

アプリケーション定義置換のセクションにて、置換文字列としてG_COLLECTION_NAME置換値CONTACT_USERSを設定します。

セッションの開始時に、このAPEXコレクションを初期化します。

共有コンポーネントアプリケーション・プロセスを開きます。

アプリケーション・プロセスの一覧が表示されます。作成を実行します。


名前コレクションの初期化ポイントとして新規インスタンス(新規セッション開始時)を選択します。

へ進みます。


APEXコレクションの作成または再初期化を行うAPI、APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTIONを呼び出すコードを記述します。

apex_collection.create_or_truncate_collection(
    p_collection_name => :G_COLLECTION_NAME
);


へ進みます。


新規にセッションが作成される際に必ず実行するため、条件タイプに何も指定しません。

プロセスの作成を実行します。


APEXコレクションを初期化するアプリケーション・プロセスが作成されました。


すでに接触追跡のアプリケーションを実行していると、セッションは開始済みになります。APEXコレクションCONTACT_USERSをアプリケーションで使用するには、一旦、実行中のアプリケーションからサインアウトし、サインインし直す必要があります。


アプリケーションの日時書式の設定



アプリケーション定義グローバリゼーションアプリケーションの日付書式YYYY-MM-DD HH24:MI:SSに設定します。


これから記述するSELECT文などから、ファンクションto_dateto_charの呼び出しを減らします。


ページの編集



これから接触追跡の結果を表示するページを編集します。

新たに対話グリッドのリージョンを作成します。

識別名前パラメータタイプとして対話グリッドを選択します。ソースタイプSQL問合せを選択し、SQL問合せとして以下を記述します。


作成した対話グリッドのリージョンは、Bodyの直下に配置します。すでに作成されているリージョンパラメータは、後に削除します。


APEXコレクションのSEQ_IDは、列IDとして認識されます。これを主キーとして扱います。レンダリング・ツリーより列IDを選択し、識別タイプ非表示ソース主キーONに変更します。


対話グリッドの編集を有効にします。

リージョンパラメータを選択し、Attributesを開いて編集有効ONにします。


APEXコレクションへの行の挿入、更新、削除を行うプロセスを変更します。

プロセス - 対話グリッド・データの保存を選択し、設定ターゲット・タイプPL/SQL Codeに変更します。

挿入/更新/削除するPL/SQLコードに、以下のコードを記述します。

APEXコレクションはAPEXセッション毎に異なるため、更新の競合を考慮する必要はありません。そのため、失われた更新の防止OFF行のロックNoにします。


次にマップ・リージョンを更新します。

マップ・リージョンContact Tracingのレイヤー接触を選択します。

ソースの位置をローカル・データベース、タイプをSQL問合せに変更し、SQL問合せとして以下を記述します。

今回の記事のメイン・テーマであるCROSS APPLYを使用して、APEXコレクションの値を表関数contact_tracingに渡しています。

送信するページ・アイテムはすべて削除します。列のマッピング経度列X緯度列Yを指定し直します。また、外観の塗りつぶしの色にも&COL.を設定し直します。


レイヤーパラメータを開き、設定済みのパラメータをすべて選択します。タイプNULLに変更し、ページの変更を保存します。

この後でリージョンの削除に失敗します。そのため、必ずこの時点で変更を保存します。


元々のアプリケーションに存在していたブレッドクラムのリージョンContact Tracingと、静的コンテンツのリージョンパラメータ削除します。


ページの保存を実行するとエラーが発生しているため、保存ができないとレポートされます。

一旦、ページ番号の横にある実行をクリックし、ページ・デザイナをリロードします。


保存されていない変更があります。変更を破棄するには「OK」を押し、現在のページに戻るには「取消」をクリックします。というダイアログが表示されます。

ここではOKをクリックします。


このような警告が表示されるのは、おそらく不具合だと思われます。リージョンの作成には失敗しますが、ページ・デザイナがリロードされることにより、パラメータに関するエラーは解消されます。

再度、リージョンの削除を実行すると、今度は正常にリージョンが削除されます。

最後に対話グリッドの内容が変更されたときにマップ・リージョンの表示されるように、動的アクションを作成します。

リージョンパラメータ上でコンテキスト・メニューを表示し、動的アクションの作成を実行します。


作成した動的アクションの識別名前マップのリフレッシュとします。タイミングイベントは、保存[対話グリッド]に変更します。選択タイプリージョンリージョンパラメータです。


TRUEアクション識別アクションとして、リフレッシュを選択します。影響を受ける要素選択タイプリージョンリージョンとしてマップ・リージョンであるContact Tracingを選択します。


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

保存と実行を行うと、本記事の先頭にあるGIF動画の動作を確認できます。

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

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