ヘッダーをスキップ

Oracle Database PL/SQLユーザーズ・ガイドおよびリファレンス
10g リリース2(10.2)

B19257-01
目次
目次
索引
索引

戻る 次へ

1 PL/SQLの概要

この章では、PL/SQL言語の主な機能について説明します。データベース・プログラミングに対するPL/SQLの機能、および他のプログラミング言語で習得した手法を再利用する方法を示します。

この章の項目は、次のとおりです。

PL/SQLのメリット

PL/SQLは完全な移植性を持つ高性能のトランザクション処理言語で、次のようなメリットがあります。

SQLとの緊密な統合

SQLは、柔軟かつ強力で、しかも覚えやすいという特長のために、標準データベース言語になりました。SELECTINSERTUPDATEDELETEなどの、いくつかの英語に似たコマンドを使用して、リレーショナル・データベースに格納されているデータを簡単に操作できます。

PL/SQLでは、SQLのすべてのファンクション、演算子および疑似列と同様に、SQLのデータ操作、カーソル制御およびトランザクション制御のすべてのコマンドを使用できます。SQLのこの拡張サポートによって、Oracleデータを柔軟かつ安全に操作できます。また、PL/SQLでSQLのデータ型が完全にサポートされているため、アプリケーションとデータベースの間でデータをやり取りする際、データを変換する必要が少なくなります。

PL/SQL言語とSQLは緊密に統合されています。SQLデータ型とPL/SQLデータ型の変換を行う必要はありません。データベースのNUMBERまたはVARCHAR2列は、PL/SQLのNUMBERまたはVARCHAR2変数に格納されます。この統合によって、学習および処理に必要な時間が短縮されます。PL/SQL言語の特別な機能によって、データ型を指定せずに表の列や行を操作できるため、表の定義が変更された場合のメンテナンス作業が簡略化されます。

PL/SQLにおけるSQL問合せの実行および結果セットの処理は、一般的なスクリプト言語でテキスト・ファイルを開いて各行を処理する場合と同様に簡単です。データベース・オブジェクトのメタデータへのアクセスおよびデータベースのエラー条件の処理にPL/SQLを使用して、データベース管理用のユーティリティ・プログラムを作成できます。このプログラムは信頼性が高く、各操作が正常に終了したかどうかの出力を読みやすい形式で生成します。PL/SQLは、トリガーやオブジェクト型など、データベースの多くの機能で使用されます。トリガー本体およびオブジェクト型のメソッドをPL/SQLで作成できます。

PL/SQLは静的SQLおよび動的SQLの両方をサポートしています。静的SQL文の構文はプリコンパイル時にわかり、その準備は実行前に行われます。一方、動的SQL文の構文は実行時までわかりません。動的SQLは、アプリケーションをより柔軟で多目的に使用できるプログラミング技術です。プログラムでは、表名やWHERE句などの詳細情報が事前にわからない場合でも、SQLデータ定義文、データ制御文、セッション制御文を実行時に作成して処理できます。PL/SQLでの静的SQLの使用の詳細は、第6章「PL/SQLでのSQL操作の実行」を参照してください。動的SQLの使用の詳細は、第7章「システム固有の動的SQLを使用したSQL操作の実行」を参照してください。動的SQLの詳細は、『Oracle Databaseアプリケーション開発者ガイド-基礎編』を参照してください。

高いパフォーマンス

PL/SQLがなければ、OracleはSQL文を1文ずつ処理する必要があります。多くのSQL文を発行するプログラムでは、データベースに対して複数回のコールを行う必要があるため、ネットワークおよびパフォーマンスのオーバーヘッドが非常に大きくなります。

PL/SQLがあれば、複数文のブロック全体をOracleに一度に送信できます。そのため、データベースとアプリケーションの間のネットワークの通信量を大幅に削減できます。図1-1に示すように、PL/SQLブロックおよびサブプログラムを使用してSQL文をグループ化してから、データベースに送信して実行することができます。PL/SQL言語には、ループの中で発行されたSQL文をさらにスピードアップする機能も備わっています。

PL/SQLストアド・プロシージャは一度コンパイルされてから実行可能なフォームで格納されるため、プロシージャ・コールは効果的です。ストアド・プロシージャはデータベース・サーバー内で実行されるため、ネットワーク上で一度コールすると大規模なジョブを開始できます。この作業の分割によってネットワークの通信量が軽減され、応答時間が改善されます。ストアド・プロシージャはキャッシュされ、ユーザー間で共有されます。これによって、必要なメモリー量と起動オーバーヘッドが減少します。

図1-1    PL/SQLによるパフォーマンスの向上


画像の説明

高い生産性

PL/SQLでは、データを操作するコードを非常にコンパクトにすることができます。Perlのようなスクリプト言語が、ファイルからデータを読み込み、変換して、書き込むのと同じように、PL/SQLは、データベースのデータを問い合せ、変換して、更新することができます。PL/SQLでは、例外処理、カプセル化、データ隠ぺいおよびオブジェクト指向のデータ型など、あらゆるソフトウェア・エンジニアリング機能が提供されているため、設計およびデバック時間を節約できます。

PL/SQLは、Oracle Formsなどのツールを拡張します。これらのツールでPL/SQLを使用すると、使い慣れた言語の構造体を使用してアプリケーションを構築できます。たとえば、複数のトリガー・ステップ、マクロまたはユーザー・イグジットを使用するかわりに、Oracle Formsトリガーの中でPL/SQLブロック全体を使用できます。また、PL/SQLはどの環境でも同じです。ある1つのOracleツールで習得したPL/SQLの知識は他のツールにも利用できます。

完全な移植性

PL/SQLで作成されたアプリケーションは、Oracleデータベースが動作する任意のオペレーティング・システムおよびプラットフォームで実行できます。したがって、PL/SQLを使用すると、様々な環境で再利用できる、移植性の高いプログラム・ライブラリを作成できます。

優れたセキュリティ

PL/SQLストアド・プロシージャは、クライアントからサーバーへアプリケーション・コードを移動します。サーバーでは、コードの改ざんの防止、コード内の細部の隠ぺいおよびアクセスの制限が可能になります。たとえば、表を更新するプロシージャへのアクセス権をユーザーに付与して、表自体またはUPDATE文のテキストへのアクセス権は付与しないようにできます。PL/SQLで作成されたトリガーは、データへの変更を制御および記録して、すべての変更がビジネス・ルールに従っていることを確認します。

PL/SQLのソース・ユニットのラップまたは隠ぺいの詳細は、付録A「PL/SQLのソース・コードの不明瞭化」を参照してください。

事前定義パッケージへのアクセス

Oracleでは、様々な実用的な作業を実行するためにPL/SQLからコールできるAPIを定義した製品固有のパッケージを提供しています。これらのパッケージには、データベースのトリガーを使用するためのDBMS_ALERT、オペレーティング・システム(OS)のテキスト・ファイルを読み書きするためのDBMS_FILE、Hypertext Transfer Protocol(HTTP)のコールアウトを実行するためのDBMS_HTTP、PL/SQLブロックおよびサブプログラムの出力を表示するためのDBMS_OUTPUT、名前付きパイプを介して通信するためのDBMS_PIPEなどがあります。これらのパッケージの詳細は、「製品固有のパッケージの概要」を参照してください。

Oracleが提供するパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

オブジェクト指向プログラミングのサポート

オブジェクト型は理想的なオブジェクト指向のモデル・ツールであり、それによって複雑なアプリケーションの構築に必要な費用と時間を節約できます。オブジェクト型を使用すると、モジュール構造で維持および再利用が可能なソフトウェア構成要素を作成できるのみでなく、複数の異なるチームのプログラマが同時にソフトウェア構成要素を開発できます。

データに対する操作をカプセル化すると、オブジェクト型を使用してデータ・メンテナンスのためのコードをSQLスクリプトやPL/SQLブロックではなく、メソッドに入れることができます。また、オブジェクト型を使用すれば、実装の細部が隠されるため、クライアント・プログラムに影響することなく細部を変更できます。第12章「PL/SQLのオブジェクト型の使用」を参照してください。

さらに、オブジェクト型を使用することで、現実のデータをモデル化できます。複雑な実世界のエンティティと関連は、オブジェクト型に直接対応付けることができます。この直接マッピングは、プログラムがシミュレートしている世界をより適切に反映するために役立ちます。オブジェクト型の情報は、『Oracle Databaseアプリケーション開発者ガイド-オブジェクト・リレーショナル機能』を参照してください。

WebアプリケーションおよびWebページ開発のサポート

PL/SQLを使用すると、WebアプリケーションおよびServer Pages(PSP)を開発できます。WebでのPL/SQLの使用の概要は、「PL/SQLを使用してWebアプリケーションおよびServer Pagesを作成する方法」を参照してください。

PL/SQLの主な特長

PL/SQLでは、SQLのデータ操作機能と手続き型言語の処理機能の両方が利用できます。IF文やLOOP文を使用すると、プログラム・フローを制御できます。その他の手続き型プログラム言語と同様に、変数の宣言、プロシージャとファンクションの定義、およびランタイム・エラーのトラップを行うこともできます。

PL/SQLを使用すると、複雑な問題を容易に理解できるプロシージャ・コードに分割し、複数のアプリケーション間でそのコードを再利用できます。単純なSQLで問題が解決できる場合、PL/SQLプログラム内でSQLコマンドを直接発行できます。新しいAPIを学習する必要はありません。PL/SQLのデータ型は、SQLの列型と対応しているため、PL/SQLの変数と表内のデータを容易に交換できます。

PL/SQLブロック構造

PL/SQLプログラムを構成する基本単位(プロシージャ、ファンクションおよび無名ブロック)は、内部で相互にネストできる論理ブロックです。ブロックは、関連する宣言および文をグループ化します。宣言は、それを使用する場所に近い場所に置くことができます。大規模なサブプログラムの内部でも可能です。宣言はブロックの中で局所的に有効で、そのブロックが終了すると消滅します。これによって、変数およびプロシージャの名前空間が一杯になることを回避できます。ブロック構造の構文の詳細は、「ブロック宣言」を参照してください。

図1-2に示すとおり、PL/SQLブロックは宣言部(DECLARE)、実行部(BEGIN ..END)およびエラー条件を処理する例外処理(EXCEPTION)部の3つの基本部分で構成されます。このうち必ず存在する必要があるのは実行部のみです。最初に記述されるのはオプションの宣言部で、ここでは型や変数などの項目を定義できます。宣言した項目は、実行部で操作できます。実行の間に起動された例外は、例外処理部で処理されます。PL/SQLブロック構造の例は、例1-3を参照してください。

図1-2    ブロック構造


画像の説明

PL/SQLのブロックまたはサブプログラムの実行部と例外処理部では、ブロックをネストできます。宣言部ではネストできません。また、どのブロックの宣言部でも、ローカル・サブプログラムを定義できます。ローカル・サブプログラムは、それが定義されているブロックからのみコールできます。

PL/SQLの変数および定数

PL/SQLでは変数と定数を宣言し、SQL文とプロシージャ文の中で、式を使用可能な任意の場所で使用できます。このため、他の文で変数と定数を参照するときは、事前に宣言する必要があります。詳細は、「宣言」を参照してください。

変数の宣言

変数は、CHARDATENUMBERなどの任意のSQLデータ型や、BOOLEANPLS_INTEGERなどのPL/SQL固有のデータ型を持つことができます。たとえば、6桁の数字が入るpart_no、ブール値TRUEまたはFALSEが入るin_stockなど、部のデータの変数を宣言します。これらの変数および前述の部の変数は、例1-1で示すように宣言します。宣言部の各行の最後には、セミコロン(;)を付けます。

例1-1    PL/SQL変数の宣言

DECLARE
  part_no    NUMBER(6);
  part_name  VARCHAR2(20);
  in_stock   BOOLEAN;
  part_price NUMBER(6,2);
  part_desc  VARCHAR2(50);

コンポジット・データ型TABLEVARRAYRECORDを使用して、ネストした表、可変サイズの配列(VARRAY)およびレコードも宣言できます。第5章「PL/SQLのコレクションおよびレコードの使用」を参照してください。

変数への値の代入

変数に値を代入する方法は3つあります。1つ目は、例1-2で示すように、コロンに等号を付けた代入演算子(:=)を使用する方法です。変数は演算子の左に、ファンクション・コールを含む式は演算子の右に置きます。変数を宣言するときに、変数に値を代入できます。

例1-2    代入演算子を使用した変数への値の代入

DECLARE
   wages          NUMBER;
   hours_worked   NUMBER := 40;
   hourly_salary  NUMBER := 22.50;
   bonus          NUMBER := 150;
   country        VARCHAR2(128);
   counter        NUMBER := 0;
   done           BOOLEAN;
   valid_id       BOOLEAN;
   emp_rec1       employees%ROWTYPE;
   emp_rec2       employees%ROWTYPE;
   TYPE commissions IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
   comm_tab       commissions;
BEGIN
   wages := (hours_worked * hourly_salary) + bonus;
   country := 'France';
   country := UPPER('Canada');
   done := (counter > 100);
   valid_id := TRUE;
   emp_rec1.first_name := 'Antonio';
   emp_rec1.last_name := 'Ortiz';
   emp_rec1 := emp_rec2;
   comm_tab(5) := 20000 * 0.15;
END;
/

変数に値を代入する2つ目の方法は、データベース値を選択またはフェッチして代入する方法です。例1-3では、従業員の給料の10%が選択され、bonus変数に代入されます。変数bonusを別の計算に使用したり、変数の値をデータベース表に挿入することができます。

例1-3    SELECT INTOを使用した変数への値の代入

DECLARE
  bonus  NUMBER(8,2);
  emp_id NUMBER(6) := 100;
BEGIN
  SELECT salary * 0.10 INTO bonus FROM employees 
    WHERE employee_id = emp_id;
END;
/

変数を値に代入する3つ目の方法は、値をOUTパラメータまたはIN OUTパラメータとしてサブプログラムに渡し、サブプログラム内で代入する方法です。例1-4では、サブプログラムに変数salを渡し、そのサブプログラムで変数を更新しています。

この例では、DBMS_OUTPUT.PUT_LINEを使用してPL/SQLプログラムの出力を表示しています。詳細は、「PL/SQLを使用したデータの入出力」を参照してください。DBMS_OUTPUTパッケージの詳細は、「DBMS_OUTPUTパッケージ」を参照してください。

例1-4    サブプログラムのパラメータとしての変数への値の代入

REM SERVEROUTPUT must be set to ON to display output with DBMS_OUTPUT
SET SERVEROUTPUT ON FORMAT WRAPPED
DECLARE
  new_sal NUMBER(8,2);
  emp_id  NUMBER(6) := 126;
  PROCEDURE adjust_salary(emp_id NUMBER, sal IN OUT NUMBER) IS  
    emp_job VARCHAR2(10);
    avg_sal NUMBER(8,2);
    BEGIN
      SELECT job_id INTO emp_job FROM employees WHERE employee_id = emp_id;
      SELECT AVG(salary) INTO avg_sal FROM employees WHERE job_id = emp_job;
      DBMS_OUTPUT.PUT_LINE ('The average salary for ' || emp_job 
                            || ' employees: ' || TO_CHAR(avg_sal));
      sal := (sal + avg_sal)/2; -- adjust sal value which is returned
    END; 
BEGIN
  SELECT AVG(salary) INTO new_sal FROM employees;
  DBMS_OUTPUT.PUT_LINE ('The average salary for all employees: ' 
                        || TO_CHAR(new_sal));
  adjust_salary(emp_id, new_sal); -- assigns a new value to new_sal
  DBMS_OUTPUT.PUT_LINE ('The adjusted salary for employee ' || TO_CHAR(emp_id) 
                        || ' is ' || TO_CHAR(new_sal)); -- sal has new value
END;
/

バインド変数

PL/SQLコードにSQLのINSERTUPDATEDELETEまたはSELECT文を直接埋め込むと、PL/SQLは、WHERE句およびVALUES句内の変数を自動的にバインド変数に変換します。これらのSQL文は、同じコードが実行されるたびにOracleによって再利用されます。異なる変数値を持つ類似する文を実行する場合、パラメータを受け取り、それらのパラメータを文の適切な部分に代入してその文を発行するストアド・プロシージャをコールすることで、解析によるオーバーヘッドを低減できます。

動的SQLの場合は、変数を通常使用する部分(WHERE句やVALUES句など)にバインド変数を指定する必要があります。リテラルおよび変数値を連結して単一の文字列にするかわりに、変数をバインド変数の名前(先頭にコロンを追加したもの)に置き換え、USING句を使用して対応するPL/SQL変数を指定します。変数を連結して文字列にするかわりにUSING句を使用すると、解析によるオーバーヘッドを低減し、OracleでSQL文を再利用することができます。次に例を示します。

'DELETE FROM employees WHERE employee_id = :id' USING emp_id;

バインド変数の使用例は、例7-1を参照してください。

定数の宣言

定数の宣言は変数の宣言と似ていますが、キーワードCONSTANTを付ける点と、定数に直接値を代入する必要がある点が異なります。後で定数に値を代入することはできません。定数の宣言を次の例に示します。

credit_limit CONSTANT NUMBER := 5000.00;

「定数」を参照してください。

PL/SQLを使用した問合せの処理

PL/SQLを使用したSQL問合せの処理は、他の言語を使用したファイルの処理と似ています。たとえば、Perlプログラムは、ファイルをオープンして内容を読み取り、各行を処理した後ファイルをクローズします。同様に、PL/SQLプログラムも、例1-5に示すとおり、問合せを発行し、結果セットから取り出した行を処理します。

例1-5    LOOPでの問合せ結果の処理

BEGIN
  FOR someone IN (SELECT * FROM employees WHERE employee_id < 120 )
  LOOP
    DBMS_OUTPUT.PUT_LINE('First name = ' || someone.first_name ||
                         ', Last name = ' || someone.last_name);
  END LOOP;
END;
/

このような単純なループを使用するか、または問合せ、データの取出しおよび処理の終了を行う個別の文を使用して処理を正確に制御することができます。

PL/SQLサブプログラムの宣言

サブプログラムは、パラメータの組を指定してコールできる、名前の付けられたPL/SQLブロックです。PL/SQLにはプロシージャとファンクションの2種類のサブプログラムがあります。次はPL/SQLプロシージャの宣言の例です。

DECLARE
  in_string  VARCHAR2(100) := 'This is my test string.';
  out_string VARCHAR2(200);
  PROCEDURE double ( original IN VARCHAR2, new_string OUT VARCHAR2 ) AS
    BEGIN
      new_string := original || original;
    END;

パッケージのサブプログラム宣言の例は、例1-13を参照してください。サブプログラムの詳細は、「サブプログラム」を参照してください。

データベースに格納されたSQL文を使用してスタンドアロン・サブプログラムを作成できます。「サブプログラム: プロシージャおよび機能」を参照してください。

PL/SQL変数のデータ型の宣言

各PL/SQL変数の宣言の一部として、変数のデータ型を宣言します。通常、このデータ型は、NUMBERまたはVARCHAR2などの、PL/SQLとSQLの間で共有されるデータ型の1つです。特別な修飾子%TYPEおよび%ROWTYPEを使用して表の列または表の行を保持する変数を宣言すると、データベースと相互作用するコードのメンテナンスがより簡単になります。データ型の詳細は、第3章「PL/SQLのデータ型」を参照してください。

%TYPE

%TYPE属性は、変数またはデータベース列のデータ型を与えます。これはデータベース値を保持する変数を宣言する場合に、特に便利です。たとえば、employeesという名前の表にlast_nameという名前の列があるとします。列titleと同じデータ型の変数v_last_nameを宣言するには、ドット表記法と%TYPE属性を次のように使用します。

v_last_name employees.last_name%TYPE;

%TYPE属性を使用してv_last_nameを宣言することには2つのメリットがあります。第1に、ユーザーはlast_nameの正確なデータ型を知る必要がありません。第2に、last_nameのデータベース定義を変更した場合(文字列の長さを増やすなど)でも、v_last_nameのデータ型はそれに応じて実行時に変更されます。

%TYPEの詳細は、「%TYPE属性の使用」および「%TYPE属性」を参照してください。

%ROWTYPE

PL/SQLではデータのグループ化にレコードを使用します。レコードは、データ値を格納できる複数の関連したフィールドから構成されます。%ROWTYPE属性は、表中の行を表すレコード型を与えます。レコードには、表から選択された行全体、あるいはカーソルまたはカーソル変数でフェッチされた行全体のデータを格納できます。「カーソル」を参照してください。

行の中の列と、それに対応するレコード中のフィールドは、同じ名前と同じデータ型を持ちます。次の例では、dept_recという名前のレコードを宣言しています。このレコードのフィールドは、departments表の列と同じ名前で同じデータ型です。

DECLARE
  dept_rec departments%ROWTYPE; -- レコード変数の宣言

次の例に示すように、フィールドの値にアクセスするにはドット表記法を使用します。

v_deptid := dept_rec.department_id;

従業員の姓、給与、入社日および役職を取り出すカーソルを宣言する場合は、例1-6に示すとおり、%ROWTYPEを使用して、同じ情報を格納するレコードを宣言できます。FETCH文を実行する場合は、employee表のlast_name列の値はemployee_reclast_nameフィールドに、salary列の値はsalaryフィールドに、というように代入されます。

例1-6    明示カーソルでの%ROWTYPEの使用

DECLARE
  CURSOR c1 IS
    SELECT last_name, salary, hire_date, job_id FROM employees 
       WHERE employee_id = 120;
-- declare record variable that represents a row fetched from the employees table
   employee_rec c1%ROWTYPE; 
BEGIN
-- open the explicit cursor and use it to fetch data into employee_rec
  OPEN c1;
  FETCH c1 INTO employee_rec;
  DBMS_OUTPUT.PUT_LINE('Employee name: ' || employee_rec.last_name);
END;
/

%ROWTYPEの詳細は、「%ROWTYPE属性の使用」および「%ROWTYPE属性」を参照してください。

PL/SQLの制御構造

制御構造は、SQLに対して加えられたPL/SQLの最も重要な機能拡張です。PL/SQLを使用すると、Oracleデータを操作できるのみでなく、IF-THEN-ELSECASEFOR-LOOPWHILE-LOOPEXIT-WHENGOTOなどの条件制御文、反復制御文および順次制御文を使用してデータを処理できます。詳細は、第4章「PL/SQLの制御構造の使用」を参照してください。

条件制御

状況に応じてアクションを選択する必要のある場面はよくあります。IF-THEN-ELSE文を使用すると、一連の文を条件に合わせて実行できます。IF句で条件を検査します。THEN句で条件がTRUEの場合のアクションを定義し、ELSE句では条件がFALSEまたはNULLの場合のアクションを定義します。例1-7では、IF-THEN-ELSEを使用して、従業員の現在の給与を基に受け取る給与の昇給額を決める場合の例を示します。

複数の値から、またはアクションの途中で選択するには、CASE構造体を使用できます。CASE式では条件が評価され、各ケースの値が戻されます。CASE文では条件が評価され、ケースごとにアクションが実行されます。アクションは、PL/SQLブロック全体の場合もあります。例1-7を参照してください。

例1-7    IF-THEN_ELSE文およびCASE文を使用した条件制御

DECLARE
   jobid      employees.job_id%TYPE;
   empid      employees.employee_id%TYPE := 115;
   sal        employees.salary%TYPE;
   sal_raise  NUMBER(3,2);
BEGIN
  SELECT job_id, salary INTO jobid, sal from employees WHERE employee_id = empid;
  CASE
    WHEN jobid = 'PU_CLERK' THEN
        IF sal < 3000 THEN sal_raise := .12;
          ELSE sal_raise := .09;
        END IF;
    WHEN jobid = 'SH_CLERK' THEN
        IF sal < 4000 THEN sal_raise := .11;
          ELSE sal_raise := .08;
        END IF;
    WHEN jobid = 'ST_CLERK' THEN
        IF sal < 3500 THEN sal_raise := .10;
          ELSE sal_raise := .07;
        END IF;
    ELSE
     BEGIN
       DBMS_OUTPUT.PUT_LINE('No raise for this job: ' || jobid);
     END;
  END CASE;
  UPDATE employees SET salary = salary + salary * sal_raise 
    WHERE employee_id = empid;
  COMMIT;
END;
/

問合せの結果を使用してアクションを選択する一連の文が、データベース・アプリケーションではよく使用されます。また、関連するエントリが別の表に見つかった場合にのみ、行の挿入や削除を実行する一連の文もよく使用されます。このような頻繁に使用される一連の文は、条件論理を使用して1つのPL/SQLブロックにまとめることができます。

反復制御

LOOP文を使用すると、一連の文を複数回実行できます。一連の文の最初の文の前にキーワードLOOPを置き、最後の文の後にキーワードEND LOOPを置きます。一連の文を連続的に繰り返す最も簡単な形式のループを次に示します。

LOOP
  -- 一連の文
END LOOP;

FOR-LOOP文では、整数の範囲を指定し、範囲中のそれぞれの整数に対して一連の文を1回実行できます。例1-8では、ループで100個の数値を挿入し、平方根、平方および平方和をデータベース表に格納します。

例1-8    FOR-LOOPの使用

CREATE TABLE sqr_root_sum (num NUMBER, sq_root NUMBER(6,2),
                           sqr NUMBER, sum_sqrs NUMBER);
DECLARE
   s PLS_INTEGER;
BEGIN
  FOR i in 1..100 LOOP
    s := (i * (i + 1) * (2*i +1)) / 6; -- sum of squares
    INSERT INTO sqr_root_sum VALUES (i, SQRT(i), i*i, s );
  END LOOP;
END;
/

WHILE-LOOP文は、ある一連の文を条件付きで実行します。ループを反復する前に条件が評価されます。条件がTRUEならば、一連の文が実行されてから、ループの先頭で制御が再開します。条件がFALSEまたはNULLならば、ループは実行されず、制御は次の文に移ります。

例1-9では、従業員120よりも指揮系統内で上位にあり、給与が$15000よりも高い最初の従業員を探しています。

例1-9    WHILE-LOOPを使用した制御

CREATE TABLE temp (tempid NUMBER(6), tempsal NUMBER(8,2), tempname VARCHAR2(25));
DECLARE
   sal            employees.salary%TYPE := 0;
   mgr_id         employees.manager_id%TYPE;
   lname          employees.last_name%TYPE;
   starting_empid employees.employee_id%TYPE := 120;
BEGIN
   SELECT manager_id INTO mgr_id FROM employees 
      WHERE employee_id = starting_empid;
   WHILE sal <= 15000 LOOP -- loop until sal > 15000
      SELECT salary, manager_id, last_name INTO sal, mgr_id, lname
         FROM employees WHERE employee_id = mgr_id;
   END LOOP;
   INSERT INTO temp VALUES (NULL, sal, lname); -- insert NULL for tempid
   COMMIT;
EXCEPTION
   WHEN NO_DATA_FOUND THEN
      INSERT INTO temp VALUES (NULL, NULL, 'Not found'); -- insert NULLs
      COMMIT;
END;
/

これ以上の処理を望まない場合、または不可能な場合は、EXIT-WHEN文でループを終了できます。EXIT文が見つかると、WHEN句の中の条件が評価されます。条件がTRUEならば、ループは終了し、制御は次の文に移ります。例1-10では、totalの値が25,000を超えたときにループが終了します。

例1-10    EXIT-WHEN文の使用

DECLARE
  total   NUMBER(9) := 0;
  counter NUMBER(6) := 0;
BEGIN
  LOOP
    counter := counter + 1;
    total := total + counter * counter;
    -- exit loop when condition is true
    EXIT WHEN total > 25000;  
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('Counter: ' || TO_CHAR(counter) || ' Total: ' || 
TO_CHAR(total));
END;
/

順次制御

GOTO文を使用すると、無条件にラベルへ分岐します。ラベルは、二重の山カッコで囲まれた未宣言の識別子で、実行可能文またはPL/SQLブロックの前に置く必要があります。例1-11で示すように、GOTO文が実行されると、ラベルが付けられた文またはブロックに制御が移ります。

例1-11    GOTO文の使用

DECLARE
  total   NUMBER(9) := 0;
  counter NUMBER(6) := 0;
BEGIN
  <<calc_total>>
    counter := counter + 1;
    total := total + counter * counter;
    -- branch to print_total label when condition is true
    IF total > 25000 THEN GOTO print_total;
      ELSE GOTO calc_total;
    END IF;
  <<print_total>>
  DBMS_OUTPUT.PUT_LINE('Counter: ' || TO_CHAR(counter) || ' Total: ' || 
TO_CHAR(total));
END;
/

条件付きコンパイル

条件付きコンパイルを使用すると、ソース・コードを削除せずに機能を条件付けすることによって、コンパイルされたPL/SQLアプリケーションの機能をカスタマイズできます。たとえば、条件付きコンパイルを使用すると、特定のデータベース・リリースに対して、PL/SQLアプリケーションのどのPL/SQL機能を使用するかを指定できます。アプリケーションの最新のPL/SQLの機能は、新しいデータベース・リリースで実行できると同時に、その同じアプリケーションが以前のデータベース・リリースと互換性を持つように、これらの機能に条件を付けることができます。また、条件付きコンパイルは、本番環境でデバッグ作業を行わずに、開発環境でデバッグを行う場合に役立ちます。「条件付きコンパイル」を参照してください。

再利用可能なPL/SQLコードの作成

PL/SQLを使用すると、アプリケーションを管理の容易な、正しく定義されたモジュールに分けることができます。PL/SQLは、このニーズに応えるために、ブロック、サブプログラム、パッケージなどのプログラム・ユニットを提供しています。これらのプログラム・ユニットは、トリガー、ストアド・プロシージャおよびストアド・ファンクションとしてデータベースにロードして再利用できます。詳細は、第8章「PL/SQLのサブプログラムの使用」および第9章「PL/SQLパッケージの使用」を参照してください。

サブプログラム: プロシージャおよび機能

PL/SQLにはプロシージャとファンクションの2種類のサブプログラムがあり、そのどちらもパラメータを取り、起動(コール)できます。「サブプログラム」を参照してください。

SQLのCREATE PROCEDURE文を使用すると、データベースに格納するスタンドアロン・プロシージャを作成できます。詳細は、『Oracle Database SQLリファレンス』の「CREATE PROCEDURE」を参照してください。SQLのCREATE FUNCTION文を使用すると、Oracleデータベースに格納するスタンドアロン・ファンクションを作成できます。詳細は、『Oracle Database SQLリファレンス』の「CREATE FUNCTION」を参照してください。これらの(スキーマ・レベルの)ストアド・サブプログラムには、SQLからアクセスできます。

例1-12に示すように、サブプログラムはプログラムのミニチュアのようなもので、ヘッダーから始まって宣言部(オプション)、実行部、例外処理部(オプション)が続きます。

例1-12    ストアド・サブプログラムの作成

-- including OR REPLACE is more convenient when updating a subprogram
CREATE OR REPLACE PROCEDURE award_bonus (emp_id NUMBER, bonus NUMBER) AS
   commission        REAL;
   comm_missing EXCEPTION;
BEGIN  -- executable part starts here
   SELECT commission_pct / 100 INTO commission FROM employees
    WHERE employee_id = emp_id;
   IF commission IS NULL THEN
      RAISE comm_missing;
   ELSE
      UPDATE employees SET salary = salary + bonus*commission 
      WHERE employee_id = emp_id;
   END IF;
EXCEPTION  -- exception-handling part starts here
   WHEN comm_missing THEN
      DBMS_OUTPUT.PUT_LINE('This employee does not receive a commission.');
      commission := 0;
   WHEN OTHERS THEN
      NULL; -- for other exceptions do nothing
END award_bonus;
/
CALL award_bonus(150, 400);

このプロシージャがコールされると、従業員番号およびボーナス額を受け取ります。この番号を使用してデータベース表から従業員のコミッション・パーセントを選択し、同時にコミッション・パーセントを小数値に変換します。次に、コミッション金額を検査します。コミッションがNULLの場合は例外が呼び出され、NULLでない場合は従業員の給与台帳レコードが更新されます。

パッケージ: PL/SQLで記述されたAPI

PL/SQLでは、論理的に関連のある型、変数、カーソルおよびサブプログラムを、通常のストアド・プロシージャより1段階上のデータベース・オブジェクトであるパッケージとしてまとめることができます。このパッケージは、SQL文がアクセスする、関連した一連のプロシージャおよび型に対して単純かつ明快なインタフェースを定義します。

通常、パッケージには仕様部と本体の2つの部分があります。仕様部はApplication Program Interfaceを定義し、ここでデータ型、定数、変数、例外、カーソル、サブプログラムなどが宣言されます。本体には、カーソルのSQL問合せおよびサブプログラムのコードが含まれます。

パッケージ仕様部を作成するには、SQLのCREATE PACKAGE文を使用します。CREATE PACKAGE BODY文でパッケージ本体を定義します。SQLのCREATE PACKAGE文の詳細は、『Oracle Database SQLリファレンス』を参照してください。SQLのCREATE PACKAGE BODY文の詳細は、『Oracle Database SQLリファレンス』を参照してください。

例1-13emp_actionsパッケージには、employees表を更新する2つのプロシージャと情報を提供する1つのファンクションが含まれます。

例1-13    パッケージおよびパッケージ本体の作成

CREATE OR REPLACE PACKAGE emp_actions AS  -- package specification
   PROCEDURE hire_employee (employee_id NUMBER, last_name VARCHAR2, 
     first_name VARCHAR2, email VARCHAR2, phone_number VARCHAR2,
    hire_date DATE, job_id VARCHAR2, salary NUMBER, commission_pct NUMBER,
    manager_id NUMBER, department_id NUMBER);
   PROCEDURE fire_employee (emp_id NUMBER);
   FUNCTION num_above_salary (emp_id NUMBER) RETURN NUMBER;
END emp_actions;
/
CREATE OR REPLACE PACKAGE BODY emp_actions AS  -- package body
-- code for procedure hire_employee
   PROCEDURE hire_employee (employee_id NUMBER, last_name VARCHAR2,
      first_name VARCHAR2, email VARCHAR2, phone_number VARCHAR2, hire_date DATE,
      job_id VARCHAR2, salary NUMBER, commission_pct NUMBER,
      manager_id NUMBER, department_id NUMBER) IS
   BEGIN
      INSERT INTO employees VALUES (employee_id, last_name, first_name, email,
       phone_number, hire_date, job_id, salary, commission_pct, manager_id,
       department_id);
   END hire_employee;
-- code for procedure fire_employee
   PROCEDURE fire_employee (emp_id NUMBER) IS
   BEGIN
      DELETE FROM employees WHERE employee_id = emp_id;
   END fire_employee;
-- code for function num_above salary
   FUNCTION num_above_salary (emp_id NUMBER) RETURN NUMBER IS
      emp_sal NUMBER(8,2);
      num_count NUMBER;
   BEGIN
      SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
      SELECT COUNT(*) INTO num_count FROM employees WHERE salary > emp_sal;
      RETURN num_count;
   END num_above_salary;
END emp_actions;
/

これらのプロシージャをコールするアプリケーションに必要なのは、パッケージの仕様部に記載されているプロシージャの名前およびパラメータのみです。パッケージ本体内の実装の細部を変更しても、アプリケーションのコールには影響しません。

例1-13で作成されたemp_actionsパッケージのプロシージャをコールするには、例1-14の文を実行します。このプロシージャは、BEGIN ..ENDブロックの中またはSQLのCALL文で実行できます。プロシージャ名には、接頭辞としてパッケージ名が使用されています。

例1-14    パッケージのプロシージャのコール

CALL emp_actions.hire_employee(300, 'Belden', 'Enrique', 'EBELDEN',
   '555.111.2222', '31-AUG-04', 'AC_MGR', 9000, .1, 101, 110);

BEGIN
  DBMS_OUTPUT.PUT_LINE( 'Number of employees with higher salary: ' || 
                         TO_CHAR(emp_actions.num_above_salary(120)));
  emp_actions.fire_employee(300);
END;
/

パッケージはデータベースに格納され、複数のアプリケーションで共有できます。パッケージ・サブプログラムを初めてコールすると、パッケージ全体がロードされてメモリーにキャッシュされるため、それ以降のコールではディスクI/Oが減少します。このように、パッケージによって再利用が促進され、複数のユーザーおよび複数のアプリケーションが存在する環境でのパフォーマンスが向上します。パッケージの詳細は、第9章「PL/SQLパッケージの使用」を参照してください。

サブプログラムがパラメータを取らない場合、PL/SQLとSQL問合せからコールされたファンクションの両方で、空のカッコを含めるか、またはカッコを省略することができます。パラメータを取らないメソッドをコールする場合、PL/SQLスコープでは空のカッコはオプションですが、SQLスコープでは必須です。

PL/SQLを使用したデータの入出力

PL/SQLのほとんどの入出力は、SQL文によるデータベース表へのデータの格納や、それらの表の問合せによるものです。PL/SQLのその他のすべてのI/Oは、他のプログラムと相互作用するAPIによるものです。たとえば、DBMS_OUTPUTパッケージには、PUT_LINEなどのプロシージャが含まれています。PL/SQL外部の結果を参照するには、DBMS_OUTPUTに渡されたデータを読み取って表示するための、SQL*Plusなどの別のプログラムが必要です。

SQL*PlusでDBMS_OUTPUTのデータを表示するには、事前に、次のSET SERVEROUTPUT ONコマンドを発行しておく必要があります。

SET SERVEROUTPUT ON

SEVEROUTPUT設定の詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』の「SQL*Plusコマンド・リファレンス」の章を参照してください。

I/O処理のその他のPL/SQL APIには、次のものがあります。

「製品固有のパッケージの概要」を参照してください。これらのAPIの一部は出力を行うだけでなく入力も受け入れますが、キーボードから入力されたデータを直接受け入れる言語機能は組み込まれていません。SQL*PlusのPROMPTおよびACCEPTコマンドを使用すると、キーボードから入力されたデータを直接受け入れることができます。

PL/SQLのデータの抽象化

データの抽象化によって、詳細な部分を必要以上に意識することなく、データの基本的なプロパティを操作できます。データ構造を一度設計した後は、データ構造を操作するアルゴリズムの設計に集中できます。

カーソル

カーソルとは、特定の文を処理する情報を保存しておく、SQLの特定のプライベート領域の名前です。PL/SQLでは、明示カーソルおよび暗黙カーソルが使用できます。PL/SQLでは、1行のみを返す問合せを含む、一連の行にあるすべてのSQLデータ操作文に対して、暗黙的にカーソルが宣言されます。複数行を返す問合せの場合は、カーソルを明示的に宣言し、その行を個別に処理できます。たとえば、例1-6では、明示カーソルを宣言します。

PL/SQLによるカーソル管理の詳細は、「PL/SQLでのカーソルの管理」を参照してください。

コレクション

PL/SQLのコレクション型を使用すると、他の言語で使用される配列、セットおよびハッシュ表に類似した高水準のデータ型を宣言できます。PL/SQLでは、配列型はVARRAY(可変サイズの配列)、セット型はネストした表、ハッシュ表は結合配列と呼ばれます。各コレクションは、すべて同じ型の要素の順序付きグループです。各要素には一意の添字が付いています。その番号によって、集合の中での要素の位置が決まります。コレクションを宣言する場合は、TYPE定義を使用します。「コレクション型の定義とコレクション変数の宣言」を参照してください。

要素を参照するには、例1-15で示すように、カッコを使用した添字表記法を使用します。

例1-15    PL/SQLのコレクション型の使用

DECLARE
  TYPE staff_list IS TABLE OF employees.employee_id%TYPE;
  staff staff_list;
  lname employees.last_name%TYPE;
  fname employees.first_name%TYPE;
BEGIN
   staff := staff_list(100, 114, 115, 120, 122);
   FOR i IN staff.FIRST..staff.LAST LOOP
     SELECT last_name, first_name INTO lname, fname FROM employees 
       WHERE employees.employee_id = staff(i);
     DBMS_OUTPUT.PUT_LINE ( TO_CHAR(staff(i)) || ': ' || lname || ', ' || fname );
   END LOOP;
END;
/

コレクションはパラメータとして渡すこともできるため、サブプログラムは任意の数の要素を処理できます。コレクションを使用すると、バルクSQLと呼ばれるパフォーマンスの高い言語機能を使用して、データベース表からデータを出し入れできます。

コレクションの詳細は、第5章「PL/SQLのコレクションおよびレコードの使用」を参照してください。

レコード

レコードのデータ構造はコンポジット型で、フィールドには様々なデータ型を含めることができます。レコードを使用すると、関連する項目を保持し、単一のパラメータでサブプログラムにこれらの項目を渡すことができます。レコードを宣言する場合は、TYPE定義を使用します。「レコードの定義と宣言」を参照してください。

例1-16に、レコードの宣言方法を示します。

例1-16    レコード型の宣言

DECLARE
   TYPE timerec IS RECORD (hours SMALLINT, minutes SMALLINT);
   TYPE meetin_typ IS RECORD (
      date_held DATE,
      duration  timerec,  -- nested record
      location  VARCHAR2(20),
      purpose   VARCHAR2(50));
BEGIN
-- NULL does nothing but allows unit to be compiled and tested
  NULL;
END;
/

%ROWTYPE属性を使用して、表の行または問合せの結果セットの行を表すレコードを宣言できます。フィールドの名前および型を指定する必要はありません。

レコードの詳細は、第5章「PL/SQLのコレクションおよびレコードの使用」を参照してください。

オブジェクト型

PL/SQLは、オブジェクト型を介したオブジェクト指向のプログラミングをサポートします。オブジェクト型は、データを操作するために必要なファンクションおよびプロシージャとともにデータ構造をカプセル化します。データ構造を形成する変数は、属性と呼ばれます。属性を操作するファンクションおよびプロシージャは、メソッドと呼ばれます。

オブジェクト型によって、大規模なシステムが複数の論理エンティティに細分化されるため、複雑さが軽減されます。これによって、モジュール構造を持ち、保持および再利用が可能なソフトウェア・コンポーネントを作成できます。オブジェクト型の定義およびメソッドのコードは、データベースに格納されます。これらのオブジェクト型のインスタンスは、表に格納するか、またはPL/SQLコード内で変数として使用できます。例1-17に、銀行口座のオブジェクト型の定義を示します。

例1-17    オブジェクト型の定義

CREATE TYPE bank_account AS OBJECT ( 
  acct_number NUMBER(5),
  balance     NUMBER,
  status      VARCHAR2(10),
  MEMBER PROCEDURE open (SELF IN OUT NOCOPY bank_account, amount IN NUMBER),
  MEMBER PROCEDURE close (SELF IN OUT NOCOPY bank_account, num IN NUMBER,
                          amount OUT NUMBER),
  MEMBER PROCEDURE deposit (SELF IN OUT NOCOPY bank_account, num IN NUMBER,
                            amount IN NUMBER),
  MEMBER PROCEDURE withdraw (SELF IN OUT NOCOPY bank_account, num IN NUMBER,
                             amount IN NUMBER),
  MEMBER FUNCTION curr_bal  (num IN NUMBER) RETURN NUMBER );
/

オブジェクト型の詳細は、『Oracle Databaseアプリケーション開発者ガイド-オブジェクト・リレーショナル機能』を参照してください。オブジェクトでのPL/SQLの使用の詳細は、第12章「PL/SQLのオブジェクト型の使用」を参照してください。

PL/SQLエラーの処理

PL/SQLでは、例外と呼ばれるエラー条件を、簡単に検出して処理できます。エラーが発生すると、例外が呼び出されます。通常の実行は中止され、制御は任意のPL/SQLブロックの末尾に記述されている特別な例外処理部に移ります。例外は、種類ごとにそれぞれ特定の例外ハンドラによって処理されます。

PL/SQLの例外処理は、C言語で使用されるような手動チェックとは異なり、すべての処理が成功したことを確認するためにチェックを挿入します。そのかわりに、Java言語の例外処理メカニズムと同様、エラー・ルーチンへのチェックおよびコールは自動的に行われます。

変数やデータベース操作などに関連する特定の一般的なエラー条件の場合、事前定義の例外が自動的に呼び出されます。たとえば、数値を0(ゼロ)で除算しようとすると、事前定義の例外ZERO_DIVIDEが自動的に呼び出されます。

エラーであると定義した条件に対して、または通常はORA-エラー・メッセージが表示されるデータベース・エラーに対応するように、独自の例外を定義できます。ユーザー定義のエラー条件を検出した場合は、RAISE文を実行します。例1-12の例外comm_missingを参照してください。この例では、コミッションがNULLの場合は例外comm_missingが呼び出されます。

通常は、例外ハンドラをサブプログラムの最後に配置して、サブプログラム内のすべての場所で発生した例外を処理します。例外が発生した部分から実行を継続するには、例外が発生する可能性があるコードをさらにBEGIN-ENDブロック内に入れ、そのコード用の例外ハンドラを含めます。たとえば、NO_DATA_FOUNDが発生する可能性があるSQL文のグループや、DIVIDE_BY_ZEROが発生する可能性がある算術演算を、それぞれ個別のBEGIN-ENDブロックに含めます。BEGIN-ENDブロックを配置してループ内に例外ハンドラを含めることで、ループの反復中に例外が発生しても、そのループの実行を継続できます。例5-38を参照してください。

PL/SQLエラーの詳細は、「PL/SQLのランタイム・エラー処理の概要」を参照してください。PL/SQLの警告の詳細は、「PL/SQLのコンパイル時の警告の概要」を参照してください。

PL/SQLアーキテクチャ

PL/SQLコンパイルおよび実行時システムは、PL/SQLブロックとサブプログラムをコンパイルして実行するエンジンです。このエンジンは、Oracleサーバーにインストールすることも、Oracle Formsのようなアプリケーション開発ツールにインストールすることもできます。

どちらの環境でも、PL/SQLエンジンは任意の適切なPL/SQLブロックまたはサブプログラムを入力として受け付けます。図1-3は、無名ブロックを処理するPL/SQLエンジンを示します。PL/SQLエンジンはプロシージャ文のみを実行し、SQL文をOracleデータベースのSQLエンジンに送信します。

図1-3    PL/SQLエンジン


画像の説明

Oracleデータベース・サーバー

通常、Oracleデータベース・サーバーはPL/SQLブロックおよびサブプログラムを処理します。

無名ブロック

無名PL/SQLブロックは、SQL*PlusやEnterprise Managerなどの対話型ツールに送信するか、またはOracleプリコンパイラやOCIのプログラムに埋め込むことができます。プログラムは、実行時にこれらのブロックをOracleデータベースに送信します。Oracleデータベースでは、これらのブロックがコンパイルおよび実行されます。

ストアド・サブプログラム

サブプログラムは、いつでも実行できるように、コンパイルしてOracleデータベースに格納できます。コンパイルされたサブプログラムは、ストアド・プロシージャまたはストアド・ファンクションと呼ばれるスキーマ・オブジェクトになり、そのデータベースに接続されている任意の数のアプリケーションから参照できます。

SQLのCREATE PROCEDURE文を使用すると、データベースに格納するスタンドアロン・プロシージャを作成できます。詳細は、『Oracle Database SQLリファレンス』の「CREATE PROCEDURE」を参照してください。SQLのCREATE FUNCTION文を使用すると、Oracleデータベースに格納するスタンドアロン・ファンクションを作成できます。詳細は、『Oracle Database SQLリファレンス』の「CREATE FUNCTION」を参照してください。

サブプログラムは、コンパイルされた小型の形式で格納されます。コールされたサブプログラムはすぐにロードされ、処理されます。サブプログラムは共有メモリー機能を使用するため、複数のユーザーが実行する場合でも、メモリーにはサブプログラムのコピーが1つのみロードされます。

パッケージ内で定義されたストアド・サブプログラムは、パッケージ・サブプログラムと呼ばれます。独立して定義されたものは、スタンドアロン・サブプログラムと呼ばれます。別のサブプログラムやPL/SQLブロック内でネストされたサブプログラムは、ローカル・サブプログラムと呼ばれます。これは他のアプリケーションからは参照できず、囲みブロック内にのみ存在します。

ストアド・サブプログラムは、モジュール構造を持ち、再利用可能なPL/SQLコードの重要な構成要素です。JavaのJARファイル、Perlのモジュール、C++の共有ライブラリまたはVisual BasicのDLLを使用する可能性がある場合は、常にPL/SQLのストアド・プロシージャ、ストアド・ファンクションおよびパッケージを使用する必要があります。

ストアド・サブプログラムは、データベース・トリガー、別のストアド・サブプログラム、Oracleプリコンパイラ、OCIアプリケーション、または対話形式でSQL*PlusやEnterprise Managerからコールできます。また、Webサーバーを構成し、WebページのHTMLをストアド・サブプログラムによって生成することで、データの入力およびレポートの生成で使用するWebインタフェースを簡単に作成できます。

例1-18では、CALL文またはBEGIN ...ENDブロックを使用して、SQL*Plusから例1-12のストアド・サブプログラムをコールする方法を示します。

例1-18    SQL*Plusからスタンドアロン・プロシージャをコールする方法

CALL award_bonus(179, 1000);

BEGIN
  award_bonus(179, 10000);
END;
/
-- using named notation
BEGIN award_bonus(emp_id=>179, bonus=>10000); END;
/

BEGIN ..ENDブロックの使用は、様々な場合に推奨されます。BEGIN ..ENDブロックからのサブプログラムのコールでは、CALL文がサポートしていない、パラメータの名前表記法または混合表記法が利用できます。名前付きパラメータの詳細は、「サブプログラムのパラメータの位置表記法、名前表記法または混合表記法」を参照してください。さらに、CALL文を使用すると、PL/SQLサブプログラムでは処理されなかった「ORA-01403: データが見つかりません。」エラーを除去できます。

PL/SQLプロシージャ・コールの例は、例8-5「位置表記法、名前表記法または混合表記法でのサブプログラムのコール」および「パラメータとしてのスキーマ・オブジェクト名の引渡し」を参照してください。CALL文の使用の詳細は、『Oracle Database SQLリファレンス』を参照してください。

データベース・トリガー

データベース・トリガーは、データベースの表、ビューまたはイベントに対応付けられているストアド・サブプログラムです。トリガーは、複数のイベントが発生した際に、1回または複数回(INSERT文、UPDATE文またはDELETE文の影響を受けた行ごとに1回)コールできます。また、イベントの発生後にトリガーをコールして、イベントを記録したり、事後処理を実行することができます。または、イベントが発生する前にトリガーをコールして、誤操作を回避したり、新しいデータをビジネス・ルールに準拠するように修正することができます。例1-19では、例1-7の処理のように、表レベルのトリガーはemployees表の給与が更新されるたびに起動されます。更新のたびに、トリガーはレコードをemp_audit表に書き込みます。

例1-19    データベース・トリガーの作成

CREATE TABLE emp_audit ( emp_audit_id NUMBER(6), up_date DATE, 
                         new_sal NUMBER(8,2), old_sal NUMBER(8,2) );

CREATE OR REPLACE TRIGGER audit_sal
   AFTER UPDATE OF salary ON employees FOR EACH ROW
BEGIN
-- bind variables are used here for values
   INSERT INTO emp_audit VALUES( :old.employee_id, SYSDATE, 
                                 :new.salary, :old.salary );
END;
/

トリガーの実行部には、プロシージャ文のみでなく、SQLデータ操作文も含めることができます。表レベルのトリガー以外にも、ビュー用のINSTEAD OFトリガーとスキーマ用のシステム・イベントのトリガーがあります。トリガーの詳細は、『Oracle Database概要』および『Oracle Databaseアプリケーション開発者ガイド-基礎編』を参照してください。SQLのCREATE TRIGGER文の詳細は、『Oracle Database SQLリファレンス』を参照してください。

Oracleのツール製品

PL/SQLエンジンを持つアプリケーション開発用Oracleのツール製品は、PL/SQLブロックとサブプログラムを処理できます。Oracleのツール製品はブロックをローカルのPL/SQLエンジンに渡します。エンジンはすべてのプロシージャ文をアプリケーション内で実行し、SQL文のみをデータベースに送信します。大部分の処理は、データベース・サーバー上ではなくアプリケーション内で行われます。ブロックにSQL文がない場合、ブロック全体がアプリケーションで実行されます。アプリケーションが条件制御や反復制御を活用できる場合は、この機能が特に便利です。

Oracle Formsアプリケーションは、フィールド・エントリの値のテストや単純な計算のためにSQL文を頻繁に使用します。この場合、かわりにPL/SQLを使用すると、データベースへのコールを回避できます。PL/SQLファンクションを使用して、フィールド・エントリを操作することもできます。


戻る 次へ
Oracle
Copyright © 2005 Oracle Corporation.

All Rights Reserved.
目次
目次
索引
索引