表TEST_CATEGORIESにカテゴリーのコード(列CATEGORY_CD)と名前(列CATEGORY_NAME)を定義し、表TEST_PARTSの主キーは、表TEST_CATEGORIESに定義されているCATEGORY_CDとPART_IDの複合主キーとして定義します。
create table test_categories (
category_cd varchar2(2 char) not null,
category_name varchar2(80 char) not null,
constraint test_categories_pk primary key(category_cd)
);
create table test_parts (
category_cd varchar2(2 char)
constraint test_parts_category_cd_fk references test_categories,
part_id varchar2(2 char) not null,
part_name varchar2(80 char) not null,
constraint test_parts_pk primary key(category_cd, part_id)
);
空のAPEXアプリケーションを作成します。名前は複合主キーとします。
アプリケーションが作成されます。
最初に表TEST_CATEGORIESのメンテナンスを行なう対話モード・レポートとフォームのページを作成します。
ページの作成をクリックします。
対話モード・レポートを選択します。
対話モード・レポートのページの名前はCategoriesとします。フォーム・ページを含めるをオンにします。フォーム・ページ名はCategoryとします。
データ・ソースは表TEST_CATEGORIESですが、主キー列CATEGORY_CDには、データを登録する人が意味のあるコードを割り当てます(いわゆる自然キーまたはナチュラルキー)。
Oracle APEXのページ生成ウィザードは主キーは自動生成される(いわゆる代理キーまたはサロゲートキー)ことを前提としてるため、データ・ソースに表TEST_CATEGORIESを指定し、主キーとしてCATEGORY_CDを選択すると、対話モード・レポートでは列CATEGORY_CDは非表示列となり、また、フォームのページでは列CATEGORY_CDに対応するページ・アイテムが非表示かつ変更不可になります。
ここでは、主キー列CATEGORY_CDを通常の列と同様に扱えるように、ROWIDを主キーとして扱うように対話モード・レポートとフォームを構成します。
データ・ソースのソース・タイプにSQL問合せを選択し、SQL SELECT文を入力に以下を記述します。
select rowid, category_cd, category_name from test_categories
主キー列CATEGORY_CDは通常の列と同じ扱いになるため、作成されたフォームでは一度割り当てたコードを変更することも可能です。一度割り当てたコードを変更させたくない場合などは、フォームのページが作成された後にページ・アイテムのタイプを表示のみにするか、読取り専用の条件を適用します。
次へ進みます。
同様に、表TEST_PARTSのメンテナンスを行なう対話モード・レポートとフォームのページを作成します。
データ・ソースのSELECT文は以下になります。
select rowid, category_cd, part_id, part_name from test_parts
LOVソースの表/ビューの名前としてTEST_CATEGORIESを選択します。
主キー列1は表TEST_CATEGORIESと同様にROWID(Rowid)を選択し、ページの作成を実行すると、表TEST_PARTSを編集するページが作成されます。
カテゴリーのコードと名前のLOVを、共有コンポーネントとして作成します。
共有コンポーネントのLOVを開きます。
作成をクリックします。
LOVの作成は最初から行います。そのまま次へ進みます。
作成するLOVの名前はCATEGORIES_LOVとします。タイプにDynamicを選択します。
次へ進みます。
次へ進みます。
列マッピングの戻り列としてCATEGORY_CD、表示列としてCATEGORY_NAMEを選択します。
LOVを作成します。
LOVとしてCATEGORIES_LOVが作成されました。
カテゴリのコードと名前を入れ替るLOVが作成されたので、表TEST_PARTSの対話モード・レポートとフォームのページに使用します。
表TEST_PARTSの対話モード・レポートのページを開き、列CATEGORY_CDを選択します。
識別のタイプをプレーン・テキスト(LOVに基づく)に変更します。LOVに先ほど作成したCATEGORIES_LOVを選択します。ヘッダーはCategory CdだったのでCdを除いてCategoryのみに変更します。
表TEST_PARTSのフォームのページを開き、ページ・アイテムP5_CATEGORY_CDを選択します。
識別のタイプをポップアップLOVに変更します。ラベルはCategoryとします。LOVのタイプに共有コンポーネントを選択し、LOVとしてCATEGORIES_LOVを設定します。
追加値の表示はオフ、NULL値の表示はオンにしてNULL表示値として- Select Category -を記述します。
以上で複合主キーを持つ表TEST_PARTSのメンテナンス画面が作成できました。
アプリケーションを実行し、実際にデータの入力を行います。
Categoriesのページを開き、以下のデータを作成します。
コード CL - 名前 Cloud
コード DB - 名前 Database
表TEST_PARTSにデータを作成します。
対話モード・レポートの列Categoryには、CATEGORIES_LOVよりCATEGORY_NAMEの値が表示されています。
対話モード・レポートのソースのSQL問合せを以下に変更します。
編集フォームのCategoryはポップアップLOVに変わっています。
このように設定することにより、一度登録した部品についてはカテゴリを変更不可にできます。
これは行の自動処理のプロセスの失われた更新の防止によって保護されています。逆に言うと、これをオフにすると既存の行が上書きできてしまいます。
select rowid, category_cd || part_id part_cd, category_cd, part_id, part_name from test_parts
ソースのSELECT文に後から追加した列は非表示列になるため、アクションの列から表示列に追加する必要があります。追加した列Part Cdは以下のように表示されます。
フォームを開くリンクはROWIDを引数としているため、対話モード・レポートの列の追加や修正の影響は受けません。
複合主キーであってもフォームとしての扱いは通常の列なので、CategoryおよびPart Idの項目は変更可能です。ただし、同じ主キーが登録済みであればORA-00001の一意制約違反のエラーが発生します。
主キーとして設定されている値を変更することはあまり無いため、これらは値が設定済みであれば変更不可とすることが望ましいでしょう。
例えばページ・アイテムP5_CATEGORY_CDであれば、読取り専用のタイプにアイテムはNULLではないを選択し、アイテムとしてP5_CATEGORY_CDを指定します。
Oracle APEXのページ作成ウィザードを使って、表TEST_PARTSの対話モード・レポートとフォームを作ると、どのようになるか確認してみます。
ROWIDを使ったページと見分けるために、ページ名は大文字にします。対話モード・レポートのページはPARTS、フォームのページはPARTです。
データ・ソースの表/ビューの名前としてTEST_PARTSを指定します。
主キー列1はCATEGORY_CD(Varchar2)、主キー列2はPART_ID(Varchar2)となります。
作成された対話モード・レポートのページを確認します。
列CATEGORY_CDについては、タイプがプレーン・テキスト(LOVに基づく)、LOVとしてCATEGORIES_LOVが設定されています。主キー列のタイプはデフォルトで非表示列ですが、複合種キーの場合は異なるのかもしれません。
列PART_IDについてはタイプが非表示列となっていたため、表示されるようにプレーン・テキストに変更します。
フォームを開く際に、一意検索をするために主キー列である列CATEGORY_CDとPART_IDの値が必要です。このとき、列CATEGORY_CDの表示値がCATEGORY_CDの値として渡されます。表示値ではなく戻り値を引数として渡すために、レポートのソースに列CATEGORY_CDの値をそのまま参照するための列を追加します。
対話モード・レポートのソースのタイプをSQL問合せに変更し、SQL問合せとして以下を記述します。列CATEGORY_CD_Vを追加しています。
select CATEGORY_CD,
PART_ID,
PART_NAME,
CATEGORY_CD CATEGORY_CD_V
from TEST_PARTS
追加した列CATEGORY_CD_Vのタイプは非表示列にします。
対話モード・レポートの属性を開き、リンクのターゲットを修正します。
ページ・アイテムP7_CATEGORY_CDに渡す値を\#CATEGORY_CD_V#\に変更します。
以上で対話モード・レポートについては、複合主キーの列もレポートに表示されるようになりました。
編集アイコンをクリックしてフォームを開くと、表示されるのはPart Nameのみです。主キーのページ・アイテムのタイプはデフォルトで非表示になります。
ページ・アイテムP7_CATEGORY_CDをP5_CATEGORY_CDと同じく、ポップアップLOVとして設定します。
ページ・アイテムP7_CATEGORY_CDは主キー項目なので、ソースの主キーはオン、セキュリティのセッション・ステート保護はチェックサムが必要 - セッション・レベルが設定されています。この設定はページ生成ウィザードによって行われます。ページ・アイテムP7_PART_IDも同様の設定になっています。
初期化フォームのプロセスは主キーがオンになっているページ・アイテムの値を、一意検索の条件とします。そのため複合主キーを構成する列に対応するページ・アイテムは、主キーがオンである必要があります。
ページ・アイテムP7_PART_IDも表示されるよう、タイプをテキスト・フィールドに変更します。ラベルはPart Idとし、検証の必須の値はオンにします。
以上の変更で、ROWIDを使ったメンテナンス画面とほぼ同様な画面が作成できました。
ただし、主キー列の指定が異なるため、ROWIDを使った場合と複合主キーを使った場合では、特に更新処理で発生するエラーが異なります。主キーをオンにしたページ・アイテムの値は変更できません。ページ・アイテムとして変更ができても、更新時にエラーが発生するか更新処理が空振りします。
すでに主キーが登録済みの行がある場合は、エラーが発生します。
主キーが存在しない場合は、更新処理が空振りします。これはUPDATE文に以下のような条件句がついているためです。対象行が存在しないため、更新処理は発生しません。
WHERE CATEGORY_CD = :P7_CATEGORY_CD and PART_ID = :P7_PART_ID
主キーがROWIDのときは、ROWIDが条件句に現れるため、列CATEGORY_CDおよびPART_IDの更新は可能です。
今回の記事は以上です。
説明に使用したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-composite-key-form.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完