PL/SQLの主な特長

PL/SQLでは、SQLのデータ操作機能と手続き型言語の処理機能の両方が利用できます。

SQLを使用して問題が解決できる場合、PL/SQLプログラムからSQL文を発行できます。新しいAPIを学習する必要はありません。

その他の手続き型プログラム言語と同様に、PL/SQLでは、定数と変数の宣言、プログラム・フローの制御、サブプログラムの定義、およびランタイム・エラーのトラップを行うこともできます。

複雑な問題を容易に理解できるサブプログラムに分割し、複数のアプリケーションで再利用できます。

ここでのトピック

エラー処理

PL/SQLでは、エラーを簡単に検出して処理できます。

エラーが発生するとPL/SQLによって例外が呼び出されます。通常の実行は中止され、PL/SQLブロックの例外処理部に制御が移ります。Cプログラムの場合のように、すべての操作をチェックして処理が成功したことを確認する必要はありません。

詳細は、「PL/SQLのエラー処理」を参照してください。

ブロック

PL/SQLソース・プログラムの基本単位はブロックで、関連する宣言および文をグループ化します。

PL/SQLブロックは、キーワードDECLAREBEGINEXCEPTIONおよびENDで定義します。これらのキーワードは、ブロックを宣言部、実行部、例外処理部に分けます。このうち必ず存在する必要があるのは実行部のみです。ブロックにはラベルを付けられます。

宣言はブロックの中で局所的に有効で、そのブロックの実行が完了すると消滅します。これによって、変数およびサブプログラムの名前空間が一杯になることを回避できます。

ブロックはネストできます。ブロックは実行可能文であるため、実行可能文を配置できる場所であれば別のブロックでも配置できます。

ブロックは、(SQL*PlusやEnterprise Managerなどの)対話型ツールに送信するか、またはOracleプリコンパイラやOCIのプログラムに埋め込むことができます。対話型ツールまたはプログラムによって、ブロックが1回実行されます。ブロックはデータベースに格納されないため、(ラベルがある場合でも)無名ブロックと呼ばれます。

無名ブロックは、メモリーにロードされるたびにコンパイルされます。このコンパイルには、次の3段階があります。

  1. 構文チェック: PL/SQL構文がチェックされ、解析ツリーが生成されます。

  2. セマンティック・チェック: 型チェックおよび解析ツリーに対する追加処理が行われます。

  3. コード生成

ノート:

無名ブロックはSQL文です。

構文の詳細は、「ブロック」を参照してください。

例2-1 PL/SQLブロック構造

この例は、PL/SQLブロックの基本構造を示しています。

<< label >> (optional)
DECLARE    -- Declarative part (optional)
  -- Declarations of local types, variables, & subprograms

BEGIN      -- Executable part (required)
  -- Statements (which can use items declared in declarative part)

[EXCEPTION -- Exception-handling part (optional)
  -- Exception handlers for exceptions (errors) raised in executable part]
END;

変数および定数

PL/SQLでは変数と定数を宣言し、式を使用可能な任意の場所で使用できます。

プログラムの実行中に、変数の値を変更できますが、定数の値は変更できません。

詳細は、「宣言」および「変数への値の代入」を参照してください。

サブプログラム

PL/SQLのサブプログラムは、繰り返し起動できる名前付きPL/SQLブロックです。

サブプログラムにパラメータが含まれている場合は、起動のたびにパラメータ値を変えることができます。PL/SQLにはプロシージャとファンクションの2種類のサブプログラムがあります。ファンクションは結果を戻します。

PL/SQLサブプログラムの詳細は、「PL/SQLサブプログラム」を参照してください。

PL/SQLでは、他の言語で記述された外部プログラムも起動できます。

詳細は、「外部サブプログラム」を参照してください。

パッケージ

パッケージとは、論理的に関連するPL/SQLの型、変数、定数、サブプログラム、カーソルおよび例外をグループにまとめたスキーマ・オブジェクトのことです。

パッケージをコンパイルしてデータベースに格納し、その内容を複数のアプリケーションで共有できます。パッケージはアプリケーションと考えることができます。

ユーザー独自のパッケージを記述できます(詳細は、「PL/SQLパッケージ」を参照してください)。Oracle Databaseで提供されている製品固有の多数のパッケージを使用することもできます。詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

トリガー

トリガーとは、データベースに格納され、データベース内で発生したイベントに応答して実行される、名前付きPL/SQLユニットです。

トリガーをイベントの前に起動する場合でもイベントの後で起動する場合でも、またトリガーをイベントごとに実行する場合でもイベントの影響を受ける行ごとに実行する場合でも、イベントを指定できます。たとえば、EMPLOYEES表がINSERT文の影響を受けるたびに実行されるトリガーを作成できます。

トリガーの詳細は、「PL/SQLトリガー」を参照してください。

入出力

PL/SQLのほとんどの入出力(I/O)は、SQL文によるデータベース表へのデータの格納や、それらの表の問合せによるものです。他のすべてのPL/SQL I/Oは、Oracle Databaseが提供するPL/SQLパッケージを使用して実行されます。

表2-1 PL/SQL I/O処理パッケージ

パッケージ 説明 参照

DBMS_OUTPUT

PL/SQLブロック、サブプログラム、パッケージおよびトリガーからの出力を表示できます。PL/SQLデバッグ情報を表示する場合に特に役立ちます。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

HTF

HTMLタグを生成するハイパーテキスト・ファンクションを含みます(たとえば、HTF.ANCHORファンクションではHTMLアンカー・タグ<A>が生成されます)。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

HTP

HTMLタグを生成するハイパーテキスト・プロシージャを含みます。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

DBMS_PIPE

同じインスタンス内の複数のセッション間で通信できます。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

UTL_FILE

PL/SQLプログラムでオペレーティング・システムのファイルに対して読取りおよび書込みを実行できます。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

UTL_HTTP

PL/SQLプログラムでHypertext Transfer Protocol(HTTP)コールアウトを実行し、HTTP経由でインターネット上のデータにアクセスできます。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

UTL_SMTP

RFC821の仕様に従って、Simple Mail Transfer Protocol(SMTP)を介して電子メールを送信します。

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス

DBMS_OUTPUTに渡される出力を表示するには、SQL*Plusなどの別のプログラムが必要です。SQL*PlusでDBMS_OUTPUTの出力を表示するには、事前に、SQL*PlusコマンドSET SERVEROUTPUT ONを発行しておく必要があります。

表2-1のパッケージに含まれるサブプログラムの一部は入力と出力表示の両方を受け入れますが、キーボードから入力されたデータを直接受け入れることはできません。キーボードから入力されたデータを直接受け入れるには、SQL*PlusコマンドPROMPTおよびACCEPTを使用します。

関連項目:

データの抽象化

データの抽象化によって、詳細な部分を必要以上に意識することなく、データの基本的なプロパティを操作できます。

初めにデータ構造を設計してから、データ構造を操作するアルゴリズムを設計できます。

ここでのトピック

カーソル

カーソルとは、特定のSQL文やPL/SQLのSELECT INTO文を処理する情報を保存しておく、SQLのプライベート領域を指すポインタです。

カーソルを使用して、結果セットの行を一度に1行ずつ取り出すことができます。カーソル属性を使用して、カーソルの状態に関する情報(文によってこれまでに影響を受けた行数など)を取得できます。

カーソルの詳細は、「カーソルの概要」を参照してください。

コンポジット変数

コンポジット変数には内部コンポーネントがあり、個別にアクセスできます。

コンポジット変数全体をサブプログラムにパラメータとして渡すことができます。PL/SQLには、コレクションとレコードという、2種類のコンポジット変数があります。

コレクションの内部コンポーネントは、常に同じデータ型であり、要素と呼ばれます。各要素には、その一意の索引によってアクセスします。リストおよび配列は、コレクションの典型的な例です。

レコードの内部コンポーネントは、データ型が異なる場合があり、フィールドと呼ばれます。各フィールドには、その名前によってアクセスします。レコード変数には、表の1行または表の1行の列の一部を格納できます。

コンポジット変数の詳細は、「PL/SQLのコレクションおよびレコード」を参照してください。

%ROWTYPE属性の使用

%ROWTYPE属性を使用すると、データベースの表またはビュー内の行の全体または一部を表すレコードを宣言できます。

このレコードは、行の全体または一部のすべての列に対して、同じ名前とデータ型のフィールドを持ちます。行の構造が変更されると、それに応じてレコードの構造も変更されます。

%ROWTYPEの構文およびセマンティクスの詳細は、「%ROWTYPE属性」を参照してください。使用方法の詳細は、「%ROWTYPE属性を使用した項目の宣言」を参照してください。

%TYPE属性の使用

%TYPE属性を使用すると、事前に宣言されている変数または列と同じデータ型のデータ項目を(データ型を知らなくても)宣言できます。

参照先項目の宣言が変更されると、それに応じて参照元項目の宣言も変更されます。%TYPE属性は、データベースの値を保持する変数を宣言する場合に特に便利です。%TYPEの構文およびセマンティクスの詳細は、「%TYPE属性」を参照してください。使用方法の詳細は、「%TYPE属性を使用した項目の宣言」を参照してください。

抽象データ型

抽象データ型(ADT)は、データ構造と、データを操作するサブプログラムで構成されています。

データ構造を形成する変数は、属性と呼ばれます。属性を操作するサブプログラムは、メソッドと呼ばれます。

ADTはデータベースに格納されます。ADTのインスタンスは、表に格納したり、PL/SQL変数として使用することができます。

ADTにより、大規模なシステムを複数の再利用可能な論理コンポーネントに分割して、複雑さを軽減できます。

静的データ・ディクショナリ・ビュー*_OBJECTSでは、ADTのOBJECT_TYPETYPEです。静的データ・ディクショナリ・ビュー*_TYPESでは、ADTのTYPECODEOBJECTです。

ADTの詳細は、「CREATE TYPE文」を参照してください。

ノート:

ADTは、ユーザー定義型およびオブジェクト型とも呼ばれます。

関連項目:

ADT(またはオブジェクト型)については、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。

制御文

制御文は、SQLに対して加えられたPL/SQLの最も重要な機能拡張です。

PL/SQLには、制御文に3つのカテゴリがあります。

  • 条件付き選択文。データ値に応じて、異なる文を実行できます。

    詳細は、「条件付き選択文」を参照してください。

  • ループ文。一連の異なるデータ値を使用して、同じ文を繰り返し実行できます。

    詳細は、「LOOP文」を参照してください。

  • 順次制御文。指定したラベル付きの文へ移動したり、または何もしないでおくことができます。

    詳細は、「順次制御文」を参照してください。

条件付きコンパイル

条件付きコンパイルによって、ソース・テキストを削除することなく、PL/SQLアプリケーションの機能をカスタマイズできます。

たとえば、次のことが可能です。

  • 最新のデータベース・リリースで新機能を使用し、古いデータベース・リリースでアプリケーションを実行する場合にそれらの新機能を無効化することができます。

  • 開発環境でデバッグ文またはトレース文をアクティブ化し、本番サイトでアプリケーションを実行する場合にそれらの文を隠ぺいすることができます。

詳細は、「条件付きコンパイル」を参照してください。

問合せ結果セットの一度に1行ずつの処理

PL/SQLでは、SQL問合せを発行し、結果セットの行を一度に1行ずつ処理できます。

基本ループを使用するか、または問合せの実行、結果の取出しおよび処理の終了を行う個別の文を使用して処理を正確に制御できます。

例2-2 問合せ結果行の一度に1行ずつの処理

この例では、基本ループを使用します。

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

結果:

First name = Steven, Last name = King
First name = Neena, Last name = Yang
First name = Lex, Last name = Garcia
First name = Alexander, Last name = James
First name = Bruce, Last name = Miller
First name = David, Last name = Williams
First name = Valli, Last name = Jackson
First name = Diana, Last name = Nguyen
First name = Nancy, Last name = Gruenberg
First name = Daniel, Last name = Faviet
First name = John, Last name = Chen
First name = Ismael, Last name = Sciarra
First name = Jose Manuel, Last name = Urman
First name = Luis, Last name = Popp
First name = Den, Last name = Li
First name = Alexander, Last name = Khoo
First name = Shelli, Last name = Baida
First name = Sigal, Last name = Tobias
First name = Guy, Last name = Himuro
First name = Karen, Last name = Colmenares