記事一覧へ戻る

掲載元
Oracle Magazine
2014年3/4月

テクノロジー:PL/SQL

  

PL/SQLをOracle Application Expressで記述する

Steven Feuerstein著Oracle ACE Director

 

記述するコードを最小限に抑え、配置場所を慎重に選び再配置して、可能な限りパッケージ化する。

 前号のPL/SQL Challengeの正解

 

前号の"高度なコール・スタック分析"で出題したPL/SQL Challengeの質問では、Oracle Database 12のUTL_CALL_STACKパッケージについて質問しました。このクイズでは、このパッケージを使用すると、ネストしたサブプログラムの名前がコール・スタックに含まれることを実例で示しました。正解は(b)のみです。

Oracle Application ExpressとPL/SQL。なんと素晴らしい組合せでしょう。それに、どこかで見たような感じを強く受けます。

Oracleアプリケーション開発テクノロジーとの付合いが長い私には、Oracle Application Expressのよさが本当によく分かります。私は1987年に入社して以来、5年間オラクルに在籍しました。この間に、PL/SQLはSQL*Forms V3で初めて使用できるようになり、その後、Oracle Databaseを基盤とするアプリケーション向けプログラミング言語としてより広く使用できるようになりました。

PL/SQLをSQL*Forms V3で使用できるとは、実にうれしいことでした。SQL*Forms V2の、使いにくく制約の多いステップベースのトリガーで操作するのではなく、本物の言語を使用して本物のアルゴリズムを記述できたのです。より複雑なロジックを処理できるアプリケーションをより速く開発できましたし、フォームの使い勝手を向上させることもできました。アプリケーションの保守が格段に容易になり、PL/SQLブロック内のロジックを読み取ることもできました。

にもかかわらず、あの比較的初期のバージョンのPL/SQLと比較的原始的なSQL*Forms V3を使っても(というか、だからこそ、でしょうか)、今、Oracle Application Expressで遭遇するのとまったく同じ課題にぶつかりました。

現在、私はOracle Application Expressを使ってPL/SQL ChallengeのWebサイト(plsqlchallenge.com)を実装し、PL/SQL、SQL、演繹的論理、データベース設計に関するクイズを毎日、毎週、毎月出題しています。バックエンド・コード(PL/SQLパッケージ)を書くのはたいてい私で、Webサイト自体はおもに息子のEliが担当していますが、2人ともこのアプリケーションの両側を行ったり来たりしています。

私たちは堅牢かつ機能豊富なサイトを非常に少人数のチームで構築できていますし、保守もできています。とはいえ、サイトの機能強化やより多くのPL/SQL Challengeプレーヤーのサポートをもっと簡単にできるようにするために、私たちもコードベースの保守性を向上させる方法を苦労して探しました。この記事では、Oracle Application Express環境でPL/SQLを記述する方法について私たちが学んだことを紹介します。

ポイントアンドクリックとコーディング

Oracle Application Expressの世界では、開発者は特定のオプションをカーソルでポイントして選択肢をクリックする操作に多くの時間を費やします。これにより、アプリケーションに多数の動作が指定されるため、コードを記述する必要は少しも(またはほとんど)ありません。これはまぎれもない高速アプリケーション開発(RAD)環境であり、極めて簡単にアプリケーションを構築できる手段ですが、そうしなければならないわけではありません。別の環境で作業する場合は、JavaScript、カスケード・スタイル・シート(CSS)、HTMLといったいつもの配役陣とPHPまたはJavaを併用して、アプリケーション全体をコードで記述(および保守)することもできます

この方法にはある種の安心感があります。すべてが自分で制御でき、アプリケーションで発生するあらゆることは、まさに自分で入力した文字のままに表記されます。ですから、変更が可能です。

アプリケーションを100%コーディングすることの欠点は、一般的に開発者の生産性が大幅に低下することと、結果として得られるコードの構造化の度合いが、Oracle Application Express(またはOracle JDeveloper)などのRADフレームワークを使って開発したアプリケーション・コードより低くなることです。フレームワークというからには、フレームワークでサポートされているルールと形式に従ってアプリケーションを構築せざるをえません。ですから、Oracle Application Expressのトレーニングを受けた他の誰かに、自分が構築したアプリケーションの保守を任せられる可能性は十分にあります。

したがって、生産性と保守性が劇的に向上するなら、多少制御力を失っても私はちっとも構いません。それでも、Oracle Application Expressの活用の仕方に注意を払わなければ、私の後に続く、PL/SQL Challengeアプリケーションを保守する人たちに、いまだもって大迷惑をかけかねない、ということも分かりました。

Oracle Application Expressの開発者にとってのおもな課題

最初にはっきりさせておきたいのですが、この記事ではOracle Application Expressでの開発に適した一般的なベスト・プラクティスについては説明しません。私は、そのようなアドバイスができるほどこの製品に精通しているわけではありません。代わりに、Oracle Application Expressの開発者が、とりわけアプリケーションのPL/SQLコードを記述するときに直面するおもな課題を中心にとりあげます。

開発者が抱える課題を集約すると、たいていはOracle Application Expressアプリケーション内のコードが多すぎてPL/SQLパッケージおよびビューに含まれるコードが少なすぎるということになります。

フレームワークが大量の作業を引き受けてくれるため、ついついフレームワークでの作業に過度に時間を費やしがちになります。このボタンをクリックして、ここで使用するHTMLウィジェットを選択し、項目の条件としていくらかコードを書き、ページレベル・プロセス(PL/SQLコードの実行とページ・レンダリングの制御などに使用するOracle Application Expressの要素)用のコードをいくらか書き足す、などです。

あるプロセスのコードを別のプロセスにコピーし、問合せをいくつも記述し、この表を更新して別の表に挿入し、などとやっていると、知らないうちに作業時間のほとんどをOracle Application Expressの中で過ごしてしまいます。

結果はどうかと言うと、複数の場所で同じ問合せを実行していたり、複数の条件に同じルールを記述していたりと、重複が大量に発生し、たちまち自分自身のアプリケーションの中で迷子になったような感覚に襲われます。

PL/SQLをOracle Application Expressで記述するときのガイドライン

Oracle Application ExpressアプリケーションのPL/SQLコードの記述時には、次のガイドラインに従うことをお勧めします。 

  • アプリケーション・ビルダー(Oracle Application Expressのアプリケーション構築用UI)で記述すべきSQL文は、レポートおよび表を移入する問合せのみです。その場合も、問合せをできる限りシンプルにするために、ビューを使用したり、一部の複雑な使用例の場合はテーブル・ファンクションを使用したりする必要があります。

  • できるだけコードの反復を避けます。このアドバイスはOracle Application Expressに限ったものではなく、高品質のプログラミング全体に該当するもっとも重要なガイドラインの1つです。

  • Oracle Application Expressアプリケーション内のコード量を最小限に抑えます。なるべく多くのコードをPL/SQLパッケージに移動します。 

この記事では、反復を回避する方法を中心に、PL/SQLコードの保守性を向上させるためにOracle Application Expressで活用できる具体的なテクニックや機能について説明します。Oracle Application ExpressアプリケーションでのSQL文の管理方法、特に、いつどのようにテーブル・ファンクションを使用するかについては、次回の記事で説明します。

パッケージおよびビューへのコードの移動

Oracle Application Expressを使用すると、開発者が記述する必要のあるコードの量を最小限に抑えながらアプリケーションを設計できます。それでも、非常に単純なアプリケーションを構築しているのでない限り、大量のSQLロジックとPL/SQLロジックを記述することになります。Oracle Application Expressに存在するコードをぎりぎりまで減らし、できるだけ多くのロジックをパッケージとビューに移動することをお勧めします(ビューについてと、Oracle Application ExpressアプリケーションでSQL文を記述するタイミングと場所がビューとどのように関係するかについては、次回の記事で説明します)。

Oracle Application Expressでアプリケーションを保守し易くするには、反復を回避し複雑さを隠す必要があります。分かりきったことですが、複数の項目に、条件による表示を制御する複雑な同じ式をコピー/貼付けすると、バグが見つかったときに、その式があるすべての場所を忘れずに変更するのは困難になります。

そのような機能はすべてファンクションに移動し、必要に応じてファンクションをコールするだけにしたほうが、ずっとよいと思いませんか。

例を見てみましょう。ページ659はPL/SQL Challenge(plsqlchallenge.com)のQuiz Detailsページです。クイズを解き終わった後や時間切れになった後にアクセスするページです。プレーヤーに表示する内容は、クイズの状況に応じて制限する必要があります。また、このページはレビューアも使用するため、レビューアがアクセスした場合はReviewer Actionsツールバーを表示します(図1)。レビューア以外の人には、スクリーン上のこの領域と他の領域を表示しないようにします。

o24plsql-f1

図1:Reviewer Actionsが表示されたQuiz Detailsページ

Oracle Application Expressアプリケーション・ビルダーでこのQuiz DetailsページにReviewer Actions領域の条件を設定する(リスト1)と、意図したとおりに動作します。ところが、ページのテストを続けていると、別の領域にある項目の表示を制御するためにこの同じ式が必要だということに気付きます。問題ありません。さっとコピー/貼付けを行って条件を適用します。あ、待ってください。同じ条件が必要な項目がほかにもあります。もう一度コピー/貼付けを行うだけで、またもや問題解決です。

コード・リスト1:Reviewer Actions領域の条件 

DECLARE
   l_dummy   CHAR (1);
BEGIN
   SELECT 'x'
     INTO l_dummy
     FROM qdb_question_reviews qr, qdb_domain_reviewers_v dr
    WHERE     dr.user_id = :ai_user_id
          AND dr.domain_reviewer_id = qr.domain_reviewer_id
          AND qr.question_id = :p659_question_id;

   RETURN TRUE;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      RETURN FALSE;
   WHEN TOO_MANY_ROWS
   THEN
      RETURN TRUE;
END; 


どうしてロジックのコピー/貼付けを行ってはいけないのでしょうか。ロジックは変化するようなものではありません。

本当でしょうか。まさにその翌日、状況は少しばかり複雑だということに私は気付きました。レビューアのほかに、クイズの作成者にもこのツールバーと他の項目を表示する必要があったのです。

非常に簡単です。そこで、Reviewer Actions領域に戻り、条件をリスト2のコードに変更します。そして、この新しい解決策をコピーして、他のページの他の領域にある他の項目に貼り付けます。1つも見落としがなければよいのですが。

コード・リスト2:Reviewer Actions領域の条件、テイク2 

DECLARE
   l_dummy       CHAR (1);
   l_author_id   PLS_INTEGER;
BEGIN
   SELECT ‘x’
     INTO l_dummy
     FROM qdb_question_reviews qr, qdb_domain_reviewers_v dr
    WHERE     dr.user_id = :ai_user_id
          AND dr.domain_reviewer_id = qr.domain_reviewer_id
          AND qr.question_id = :p659_question_id;

   RETURN TRUE;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      SELECT qu.author_id
        INTO l_author_id
        FROM qdb_questions qu
       WHERE qu.question_id = question_id_in;

      RETURN l_author_id = :ai_user_id;
   WHEN TOO_MANY_ROWS
   THEN
      RETURN TRUE;
END; 


でも、項目の見落としがあったらどうすればよいでしょうか。それに、生産性についてはどうでしょうか。そして最後ですが、とうてい軽視できないことがあります。ほかの人たちがこのページを保守しなければならないときはどうなるでしょうか。アプリケーションを修正またはアップグレードするときに、変更が必要な箇所が大量にあるということを、いったいどうしたらほかの人たちが理解できるでしょうか。

もっとよい方法が確かにあるはずです。このロジックをパッケージのいずれかに移動し、パッケージをファンクションの中に隠し、このファンクションをアプリケーション・ビルダーでコールします。

そこで、qdb_review_mgrパッケージを開き、次のIS_REVIEWER_OR_AUTHORファンクションをパッケージ仕様部に追加します。 

FUNCTION is_reviewer_or_author (
   user_id_in       IN INTEGER,
   question_id_in   IN INTEGER)
   RETURN BOOLEAN 


実装は、Reviewer Actions領域の条件での実装とまったく同じで、ファンクション・ヘッダーを追加します。

次に、P659_IS_REV_OR_AUTHという名前の項目を作成し、この項目の値を設定するOn Load - Before Headerプロセスも加えます(リスト3のコード)。

コード・リスト3:P659_IS_REV_OR_AUTH/On Load - Before Headerプロセスのコード 

BEGIN
   CASE
      WHEN    qdb_review_mgr.is_reviewer_for_quest_domain (
                 :ai_user_id,
                 :p659_question_id)
           OR qdb_content.question_author_id (:p659_question_id) =
                 :ai_user_id
      THEN
         :p659_is_rev_or_auth := qdb_config.c_yes;
         :p659_show_answers := qdb_config.c_yes;
      ELSE
         :p659_is_rev_or_auth := qdb_config.c_no;
   END CASE;
END; 


この方法ではなく、計算を作成して、アプリケーションまたはページ項目の値を具体的に設定したほうがよい、と提案する経験豊富なOracle Application Express開発者もいるかもしれません。そのとおりだと思いますが、私はこのPL/SQLブロックにある別の項目の値(P659_IS_REV_OR_AUTHのロジックと同じロジックで決定される)も設定します。計算は項目に固有であるため、このコンテキストではプロセスのほうが理にかなっています。

これで、この領域とすべての項目の条件は次のような単純なものになります。 

:P659_IS_REV_OR_AUTH = qdb_config.c_yes 


(はい、そうです。私はOracle Application ExpressのコードにYをハードコーディングしないようにしています。)

このロジックをパッケージ・ファンクションに移動することで、ページ659のロジックが大幅にすっきりし、この先バグが入り込む危険が減るだけでなく、アプリケーションの中の再利用可能なコードの割合も増えます。IS_REVIEWER_OR_AUTHORファンクションは、アプリケーション内の他のパッケージ・サブプログラムや他のページからコールできます(また、実際にコールしています)。

Oracle Application Expressソフトウェアの開発を指揮するJoel Kallmanもアドバイスしていますが、このロジックをOracle Application Expressの認可スキームとして定義し、必要な場所で必ずこのスキームを適用すれば、簡素化と再利用をさらに勧めることができます。こうすることの利点の1つは、特定の認可スキームが使用されているすべての場所を、アプリケーション・ビルダーですばやく識別できる点です。認可スキームは、(上で実装した)条件による表示とさほど違いません。しかし、認可スキームが通常使用されるのは、もちろん認可に対してであり、それがこのファンクションの目的です。

この同じプロセスをアプリケーション全体およびチーム内の開発者全員に徹底すると、再利用可能なコード(事前に定義したファンクションおよびプロシージャをコールする程度で済む新しいサブプログラム、新しい条件、および新しいプロセス)が一種の臨界点に達していることにすぐに気付くでしょう。

アプリケーションからバックエンド・サブプログラムに情報を渡す方法にも、大いに注意を払う必要があります。Oracle Application Express Vファンクションを使用すると、項目の値を項目名から取得できます。ですから、IS_REVIEWER_OR_AUTHORファンクションはリスト4のように記述することもできました

コード・リスト4:Vファンクションを使用するパラメータレス・ファンクション 

FUNCTION is_reviewer_or_author
   RETURN BOOLEAN
IS
   l_dummy       CHAR (1);
   l_author_id   PLS_INTEGER;
BEGIN
   SELECT 'x'
     INTO l_dummy
     FROM qdb_question_reviews qr, qdb_domain_reviewers_v dr
    WHERE     dr.user_id = v ('ai_user_id')
          AND dr.domain_reviewer_id = qr.domain_reviewer_id
          AND qr.question_id = v ('p659_question_id');

   RETURN TRUE;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      SELECT qu.author_id
        INTO l_author_id
        FROM qdb_questions qu
       WHERE qu.question_id = v ('p659_question_id');

      RETURN l_author_id = v ('ai_user_id');
   WHEN TOO_MANY_ROWS
   THEN
      RETURN TRUE;
END; 


そして、次の方法でアプリケーション・ビルダーからファンクションをコールすることもできます。 

IF qdb_review_mgr.is_reviewer_or_author 
THEN 

あいにく、このアプローチには2つの大きな問題があります。
  1. 項目の名前が変わるようなことがあっても、その名前変更はリテラルの中に"隠され"、テストするまで、すなわちコンパイル時ではなく実行時まで分かりません。

  2. アプリケーションの保守担当者は、ファンクション・コールを見てもそれが何に依存しているのか分かりませんから、パッケージ本体を開いてコードを探し出すことが必要になります。

IS_REVIEWER_OR_AUTHORファンクションにVファンクションを使用するこのアプローチにはパラメータがありません。変わりに、必要な項目をファンクション内部から名前で参照します。Vファンクションをコールする代わりに、リスト5に示すように、すべての項目値をパラメータでファンクションおよびプロシージャに渡すことをお勧めします。


コード・リスト5:
パラメータ化ファンクションとしてのIS_REVIEWER_OR_AUTHORファンクション 

CREATE OR REPLACE FUNCTION is_reviewer_or_author (
   user_id_in          INTEGER,
   question_id_in   IN INTEGER)
   RETURN BOOLEAN
IS
   l_dummy       CHAR (1);
   l_author_id   PLS_INTEGER;
BEGIN
   SELECT 'x'
     INTO l_dummy
     FROM qdb_question_reviews qr, qdb_domain_reviewers_v dr
    WHERE     dr.user_id = user_id_in
          AND dr.domain_reviewer_id = qr.domain_reviewer_id
          AND qr.question_id = question_id_in;

   RETURN TRUE;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      SELECT qu.author_id
        INTO l_author_id
        FROM qdb_questions qu
       WHERE qu.question_id = user_id_in;

      RETURN l_author_id = user_id_in;
   WHEN TOO_MANY_ROWS
   THEN
      RETURN TRUE;
END; 


パラメータ化ファンクションを使用すると、このファンクションをコールするプロセスまたは条件をコンパイルするときに、項目名の綴りが間違っていないか(および、そのために未定義になっていないか)どうかをOracle Application Expressでチェックできます。しかも、アプリケーション内でこのファンクションをコールしている部分を読めば、ファンクションがユーザーIDの値と質問IDの値に依存していることが誰にでもすぐ分かり、コードの保守が格段に容易になります。

さて、ここまでコードの繰り返しを避け複雑さを隠ぺいする方法についての極めて具体的な1つの例を見てきましたので、そろそろ一般的なガイドラインについて見てみましょう。
  1. Oracle Application Expressアプリケーションのコード量をできる限り抑えること。プロセスや条件に大量の無名ブロックを記述するのではなく、そのコードをストアド・プログラム・ユニットに移動して、"ファット"コードを"シン"サブプログラム・コールに置き換えます。
  2. パラメータを介して項目値をストアド・サブプログラムに渡すこと。Vファンクションの使用を避け、変数の値を変数名で取得します。
  3. スキーマレベルのファンクションまたはプロシージャを作成しないこと。代わりに、パッケージだけを使用します。スキーマレベルのファンクションまたはプロシージャ(CREATE OR REPLACE PROCEDURE)よりパッケージをお勧めします。バックエンド・コードを悪夢に変えない唯一の方法はパッケージを使用することです。

繰り返しますが、PL/SQL Challengeアプリケーションのバックエンドは、40個のパッケージにまとめた1,900を超えるプロシージャとファンクションで構成されていて、例としては最適です。メイン・パッケージの1つ、qdb_content(QDBは、PL/SQL Challengeのアプリケーション接頭辞で、Quiz Databaseを表します)は、クイズの内容を管理します。このパッケージには180のプロシージャとファンクションが含まれています(そして、パッケージ本体には6,800行を超えるコードが含まれており、Oracle Magazine2013年9/10月号の"PL/SQLの機能強化"で紹介した、パッケージが大きくなりすぎたら分割して管理性を高めること、という別のベスト・プラクティスとテクニックが思い出されます。Oracle Database 12cにはACCESSIBLE_BY句があり、より簡単に管理性を高めることができます)。

処理内容を絞り込んだ多数のパッケージに独自のコードを組み込み、処理内容を類推できる名前をパッケージに付けておくと、既存のサブプログラムを見つけたり新しいサブプログラムを組み込むべき場所を判断したりするのが容易になります。できるだけ多くのロジックをパッケージに移動することも、パッケージを再コンパイルするだけでロジックの基本的な変更やバグ修正ができる可能性を大幅に高めます。

置換文字列の使用

リテラル値はいつか変わる可能性があるため、アプリケーションにリテラル値をハードコーディングするべきではない、ということは誰でも知っています。PL/SQLコード内でリテラルをハードコーディングしないようにする方法としては、定数を宣言して定数の名前の後ろに値を"隠す"やり方が優れています。

Oracle Application Expressでは、まだ多くの場所でこの定数を参照できますが、置換文字列、つまりアプリケーション・レベルで定義した静的変数(定数)を使用することも検討する必要があります。置換文字列の値は、次の構文を使用してアプリケーション全体で参照できます。 

&STRING_NAME. 


たとえば、PL/SQL Challengeでは、クイズを出題するための汎用プラットフォームをEliと私が構築しました。このプラットフォームを別の用途で使用する場合に必ずしもPL/SQL Challengeと呼ぶ必要がないため、次のように、この名前の表示部分の一部に置換文字列を使用しています。 

Welcome to the &PLCH_QUIZ_NAME.! 


置換文字列を慎重に使用すれば、独自アプリケーションの保守コストが減り、アプリケーションの柔軟性が増加します。置換文字列を使用することのもう1つの副次的な利点は、サポート・オブジェクトを持つアプリケーションのインストール中に置換文字列を変更できる点です(サポート・オブジェクトとはOracle Application Expressの機能ですが、スペースが限られているため、この記事で説明することはできません)。

複数ページ間でのLOVの共有

表に外部キー制約を定義してある場合はほぼ間違いなく、列または項目の有効な値をユーザーに選択してもらうための値のリスト(LOV)をアプリケーションで多数使用することになります。うれしいことに、Oracle Application Expressにはアプリケーション全体で再利用できるLOVウィジェットが組み込まれています。ところが困ったことに、気を付けないとこれらのLOVで大量の重複が簡単に発生しかねません。

私はPL/SQL Challengeアプリケーションでこの問題にぶつかりました。このアプリケーションでは複数の"ドメイン"(SQL、PL/SQLなど)に関するクイズを出題していますが、ドメインにはそれぞれ独自のバージョンがあります。クイズを定義する場合は、そのクイズの最低バージョンを指定します。プレーヤーは最低バージョンでクイズを選別することもできるため、いろいろなページでLOVが必要となり、各ページでは、次に示すように、LOVの問合せのWHERE句でドメインIDを使用します。 

SELECT version_name display, 
       domain_version return_value
  FROM qdb_domain_versions
 WHERE domain_id = :p2010_domain_id; 


そこで、Oracle Application Expressを使用する通常のケースと同じように、何も考えずに極めて効率よくアプリケーションを構築します。そしてある日、LOVのリストを眺めていると、図2に示すように、対象のページが異なる以外はどれも同じリストを提供しているように見える3つの異なるLOVが存在することに気付きます。

o24plsql-f2

図2:3つのドメイン別バージョンのLOV

これらのLOVの名前を見るだけで私は身震いがします。ページ番号以外は同じなのです。データの正規化について学んだ開発者の私には、使用される場所に関する情報を名前に含めるのは間違っているような気がします。それでも、異なるページ項目別に各LOVをフィルタする必要があるため、これ以外の方法はないと考えます。それとも、ほかに選択肢があるのでしょうか。

はっきりさせるために、これらのLOVのソース問合せを開くと、この考えが本当に正しいと分かります。これらのLOVの相違点は、下の2010と2051のLOVの問合せに示すとおり、WHERE句で異なるページ項目を使用している部分だけです。 

SELECT version_name display_value,
       domain_version_id return value
  FROM qdb_domain_versions
 WHERE domain_id = :p2010_domain_id
ORDER BY 1

SELECT version_name display_value,
       domain_version_id return value
  FROM qdb_domain_versions
 WHERE domain_id = :p2051_domain_id
ORDER BY 1 


Oracle Application Expressのエキスパートにはほど遠い私にも、ページ固有の項目参照は名前付きLOVの内部に閉じ込めない方がよいだろう、ということはすぐに分かります。これらのLOVは単一ページ内に"ある"ものではなく、理論的にはアプリケーション全体で使用できます。

とはいえ、LOVのページ参照の使用には制約があるか、さらに悪ければエラーが発生しやすくなります。LOVを正規化する方法はきっとあるはずです。

そして、実際にあります。動的問合せでLOVを定義できるのです。そこで、名前にページ番号も含まなければ、ページ項目参照を問合せにハードコーディングしてもいない新しいLOVを作成します(図3)。さて、このLOVを使用するための唯一の要件は、Oracle Application Expressアプリケーションの現在のページにフォームの項目が含まれていなければならないことです。

o24plsql-f3

図3:動的問合せを使用した新しいLOV 

:PNNNN_domain_id 


上のNNNNはページ番号です。したがって、完全に汎用とは言えませんが、これで問題は解決されます。これで、いくつかのLOVを削除し、どのページでも使用できる単一のLOVと置き換えることができます。

これで、(最悪の)ハードコーディングや、繰返しとはお別れです。

この経験から、私はいくつかのことを学びました。 

  • Oracle Application Expressチームはこのような問題を想定していると考えること。

  • 最適でないと思われることを実行している場合は、ドキュメント、特にインライン・ヘルプをチェックすること。

  • 常に、取り得るアプローチのなかでもっともソフトコーディングの動的アプローチを使用すること。 

可能なときは宣言的なロジックを使用する

次のステップ 


ダウンロード
 Oracle Database 12c
 Oracle Application Express

 テスト PL/SQLの知識

 Feuersteinのその他の記事を読む  

詳細情報
 Oracle Database 12c
 PL/SQL
 Oracle Application Express

アプリケーションのコードを記述しすぎないようにするには、そもそもコードを記述しないのが最善の方法です。ですから、可能な場合は必ずアプリケーション・ビルダーの宣言的な要素を活用するべき、ということを改めて説明して、この記事を締めくくろうと思います。

たとえば、項目、領域、または他のUI要素をアプリケーション・ページでレンダリングする場合、ロジックを記述して指定するのはごく普通です。Oracle Application Expressには、記述するのではなく選択できる事前定義済みの条件タイプと検証が多数用意されています。

ユーザーが数字だけを入力でき、文字は入力できないフィールドが必要だとします。文字列が有効な数であるかどうかをチェックするファンクションを構築することも、確かにできます(ヒント:TO_NUMBERを使用します)。しかし、もっと自信を持って言えるのは、項目を定義すれば、その項目に対して文字列の比較検証を作成し、項目が数であるべきだと指定できる、ということです。

ある項目を表示する必要があるのは、別の項目がNULL以外の場合のみであれば、次のようなコードを記述するのではなく、その項目に条件を定義し、事前定義済みの"Value of Item / Column in Expression 1 is not NULL"を選択します。 

:P203_my_item IS NOT NULL 


Oracle Application Expressの組込み要素を使用することで、生産性が向上するだけでなく、コードの量(および保守コスト)が縮小し、ほぼ間違いなくアプリケーションのパフォーマンスが向上します。このロジックはOracle Application Expressのフレームワークに"焼き付けられて"いるからです。

コードをすっきりさせてユーザーの満足度を向上

自分の好きなようにコードを書くことができ、それを他の開発者が保守できる場合はよいのですが、本当に問題になるのはユーザーへの影響です。

Oracle Application Expressを使用すると、アプリケーションを迅速に構築できるうえ、変化し続けるユーザー要件に合わせてアプリケーションを長期にわたり変更できます。アプリケーション内のコードの記述方法に無頓着でいると、ユーザーの要求に対応していくことが徐々に困難になるでしょう。

逆に、注意して繰返しを避け、入念に設計されたパッケージ・インタフェースの背後にアプリケーションの複雑なロジックを隠していれば、ユーザーの要求に応えるのが容易になり、ひいてはユーザーの満足度を維持するのも容易になります。

次回の記事では、アプリケーション・ビルダーでSQL文を記述するもっともよい方法(およびタイミング)に関する課題をとりあげます。



クイズにチャレンジ

 

PL/SQLに関するそれぞれの記事では、記事の中で説明した情報の知識をテストするクイズを毎回出題しています。このクイズは以下の他、PL/SQL Challenge(plsqlchallenge.com)にも掲載されています。PL/SQL Challengeは、PL/SQL言語やSQL、Oracle Application Express、データベース設計、および演繹的論理に関するオンライン・クイズを提供するWebサイトです。

この記事のクイズ:

従業員が好きなアイスクリームのフレーバーを表示および管理するアプリケーションを構築しようとしています。従業員の好みのフレーバーがチョコレートで、アイスクリームにナッツが含まれている場合のみ、項目を表示する必要があります。次のアプローチのいずれを使用すれば、このアプリケーションが完成するでしょうか(項目名はすべて有効とします)。

a. 次のように項目に条件を定義します。

BEGIN
   RETURN     :p100_favorite_flavor = 'CHOCOLATE'
          AND :p100_contains_nuts = 'Y';
END;
/

 

b. 次のファンクションを作成します。

CREATE OR REPLACE FUNCTION is_nutty_chocolate
   RETURN BOOLEAN
IS
BEGIN
   RETURN     v ('p100_favorite_flavor') = 'CHOCOLATE'
          AND v ('p100_contains_nuts') = 'Y';
END;
/

 

次のように項目に条件を定義します。

 

BEGIN
   RETURN is_nutty_chocolate;
END;
/


c.
次のファンクションを作成します。

CREATE OR REPLACE FUNCTION is_nutty_chocolate (
   fav_flavor_in      IN VARCHAR2,
   contains_nuts_in   IN VARCHAR2)
   RETURN BOOLEAN
IS
BEGIN
   RETURN fav_flavor_in = 'CHOCOLATE' 
          AND contains_nuts_in = 'Y';
END;
/

 

次のように項目に条件を定義します。

 

BEGIN
   RETURN is_nutty_chocolate ( :p100_favorite_flavor,
                              :p100_contains_nuts);
END;
/

 

d. 次のパッケージを作成します。

 

CREATE OR REPLACE PACKAGE favorite_mgr
IS
   FUNCTION is_nutty_chocolate (fav_flavor_in      IN VARCHAR2,
                                contains_nuts_in   IN VARCHAR2)
      RETURN BOOLEAN;
END;
/

CREATE OR REPLACE PACKAGE BODY favorite_mgr
IS
   FUNCTION is_nutty_chocolate (fav_flavor_in      IN VARCHAR2,
                                contains_nuts_in   IN VARCHAR2)
      RETURN BOOLEAN
   IS
   BEGIN
      RETURN     fav_flavor_in = 'CHOCOLATE'
             AND contains_nuts_in = 'Y';
   END;
END;
/

 

次のように項目に条件を定義します。

 

BEGIN
   RETURN favorite_mgr.is_nutty_chocolate (
             :p100_favorite_flavor,
             :p100_contains_nuts);
END;
/



Steven Feuersteinの顔写真


Steven Feuersteinの略歴および彼がOracle Magazineに投稿したPL/SQLに関する他の記事へのリンク

 

▲ ページTOPに戻る

記事一覧へ戻る