以下のような相談があったので、どのような実装ができるのか紹介します。
都道府県と市町村ごとに、その土地のお土産を一覧する画面を作ります。お土産は複数ありますが、表示は一行、編集も市町村ごとに行いたい、というのが要件です。画面上はお土産をひとまとめに編集しますが、表にはお土産ひとつひとつを1行として保存します。
クイックSQLのモデルは以下です。
# prefix: sve
# semantics: default
souvenirs
prefecture vc40 /nn
city vc80 /nn
item vc80 /nn
SQLワークショップのユーティリティからクイックSQLを開きます。上記のモデルを左ペインに入力し、SQLの生成、SQLスクリプトを保存、レビューおよび実行を行い、表SVE_SOUVENIRSを作成します。アプリケーションの作成は行いません。
表が作成されたら、空のアプリケーションを作成します。アプリケーション・ビルダーからアプリケーション作成ウィザードを実行します。名前は土産管理とします。
アプリケーションが作成されたら、お土産の一覧表示と入力/編集/削除をする画面を作成します。ページの作成を実行します。
レポート・タイプは対話モード・レポート、レポート・ページ名としてお土産一覧、フォーム・ページ名はお土産編集とします。フォーム・ページ・モードはモーダル・ダイアログを選択します。以上を設定し、次に進みます。
ナビゲーションのプリファレンスとして、新規ナビゲーション・メニュー・エントリの作成を選択し、次に進みます。
select
prefecture,
city,
listagg(item, ',') within group (order by item) items
from sve_souvenirs
group by prefecture, city
お土産については、都道府県、市町村ごとに、LISTAGG集計関数を使って、カンマ区切りで一項目にまとめます。
主キー列、2次キー列となっている列はデフォルトでタイプが非表示になるため、タイプをプレーン・テキストに変更します。列PREFECTUREとCITYの両方を選択し、識別のタイプをプレーン・テキストに変更します。
続いて、ページ・デザイナでフォームを開きます。
ページ・アイテムP3_PREFECTUREのタイプを非表示からテキスト・フィールドに変更し、ラベルにPrefectureを設定します。ページ・アイテムのプロパティ必須の値はONにすべきですが、画面サイズの都合でスクリーンショットには含んでいません。
同様にページ・アイテムP3_CITYもタイプをテキスト・フィールドに変更し、ラベルにCityを設定します。
集計関数を含むSQLを対象とした更新処理はできないため、フォームのプロセスを変更します。
設定のターゲット・タイプをPL/SQL Codeに変更し、挿入/更新/削除するPL/SQLコードとして以下を記述します。
begin
case
when :APEX$ROW_STATUS = 'C' then
insert into sve_souvenirs(prefecture, city, item)
select :P3_PREFECTURE, :P3_CITY, trim(column_value)
from apex_string.split(:P3_ITEMS, ',')
where trim(column_value) is not null;
when :APEX$ROW_STATUS = 'U' then
-- 未登録のお土産があれば、挿入する。
insert into sve_souvenirs(prefecture, city, item)
select prefecture, city, item
from
(
select :P3_PREFECTURE prefecture, :P3_CITY city, trim(column_value) item
from apex_string.split(:P3_ITEMS, ',')
where trim(column_value) is not null
minus
select prefecture, city, item
from sve_souvenirs
where prefecture = :P3_PREFECTURE and city = :P3_CITY
);
-- 更新対象に含まれない既存のお土産を削除する。
delete from sve_souvenirs
where
(prefecture, city, item)
in
(
select prefecture, city, item
from sve_souvenirs
where prefecture = :P3_PREFECTURE and city = :P3_CITY
minus
select :P3_PREFECTURE prefecture, :P3_CITY city, trim(column_value) item
from apex_string.split(:P3_ITEMS, ',')
where trim(column_value) is not null
);
when :APEX$ROW_STATUS = 'D' then
delete from sve_souvenirs
where prefecture = :P3_PREFECTURE and city = :P3_CITY;
end case;
end;
Region Sourceの設定では行のロックができないので、行のロックをPL/SQL Codeに変更し、以下のコードを設定します。
declare
r sve_souvenirs%rowtype;
begin
select * into r from sve_souvenirs
where 1=1
and prefecture = :P3_PREFECTURE
and city = :P3_CITY
for update nowait
;
end;
以上でアプリケーションの作成が完了しました。作成したアプリケーションを実行すると、表題のGIF動画の動作を確認できます。
表SVE_SOUVENIRSの内容を確認すると、列ITEMにお土産がひとつづつ登録されていることが確認できます。
以上です。
行のロック時間を調整したい場合は、PL/SQLのコードに含まれるselect for update文にwait指定を含めるようにします。
今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/souvenir-management.sql
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完