642
PL/SQL ユーザーズ・ガイドおよびリファレンス 10g リリース 110.1部品番号 部品番号 部品番号 部品番号 : B13501-01 2004 2

PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

Embed Size (px)

Citation preview

Page 1: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQLユーザーズ・ガイドおよびリファレンス

10g リリース 1(10.1)

部品番号部品番号部品番号部品番号 : B13501-01

2004 年 2 月

Page 2: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ユーザーズ・ガイドおよびリファレンス , 10g リリース 1(10.1)

部品番号 : B13501-01

原本名 : PL/SQL User’s Guide and Reference, 10g Release 1 (10.1)

原本部品番号 : B10807-01

原本著者 : John Russell

原本協力者 : Shashaanka Agrawal、Cailein Barclay、Dmitri Bronnikov、Sharon Castledine、Thomas Chang、Ravindra Dani、Chandrasekharan Iyer、Susan Kotsovolos、Neil Le、Warren Li、Bryn Llewellyn、Chris Racicot、Murali Vemulapati、Guhan Viswanathan、Minghui Yang

Copyright © 1996, 2003 Oracle Corporation. All rights reserved.

制限付権利の説明

このプログラム(ソフトウェアおよびドキュメントを含む)には、オラクル社およびその関連会社に所有権のある情報が含まれています。このプログラムの使用または開示は、オラクル社およびその関連会社との契約に記された制約条件に従うものとします。著作権、特許権およびその他の知的財産権と工業所有権に関する法律により保護されています。

独立して作成された他のソフトウェアとの互換性を得るために必要な場合、もしくは法律によって規定される場合を除き、このプログラムのリバース・エンジニアリング、逆アセンブル、逆コンパイル等は禁止されています。

このドキュメントの情報は、予告なしに変更される場合があります。オラクル社およびその関連会社は、このドキュメントに誤りが無いことの保証は致し兼ねます。これらのプログラムのライセンス契約で許諾されている場合を除き、プログラムを形式、手段(電子的または機械的)、目的に関係なく、複製または転用することはできません。

このプログラムが米国政府機関、もしくは米国政府機関に代わってこのプログラムをライセンスまたは使用する者に提供される場合は、次の注意が適用されます。

U.S. GOVERNMENT RIGHTS

Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation, and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the Programs, including documentation and technical data, shall be subject to the licensing restrictions set forth in the applicable Oracle license agreement, and, to the extent applicable, the additional rights set forth in FAR 52.227-19, Commercial Computer Software--Restricted Rights (June 1987). Oracle Corporation, 500 Oracle Parkway, Redwood City, CA 94065.

このプログラムは、核、航空産業、大量輸送、医療あるいはその他の危険が伴うアプリケーションへの用途を目的としておりません。このプログラムをかかる目的で使用する際、上述のアプリケーションを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。万一かかるプログラムの使用に起因して損害が発生いたしましても、オラクル社およびその関連会社は一切責任を負いかねます。

Oracle は Oracle Corporation およびその関連会社の登録商標です。その他の名称は、Oracle Corporation または各社が所有する商標または登録商標です。

Page 3: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

目次目次目次目次

はじめにはじめにはじめにはじめに .......................................................................................................................................................................... xv

対象読者 ................................................................................................................................................................... xviこのマニュアルの構成 ........................................................................................................................................... xvi

関連ドキュメント ................................................................................................................................................... xix表記規則 ................................................................................................................................................................... xixサンプル・データベース表 .................................................................................................................................. xxii

構文図の読み方 ...................................................................................................................................................... xxii

PL/SQL の新機能の新機能の新機能の新機能 .................................................................................................................................................. xxiii

Oracle Database 10g の PL/SQL の新機能 ....................................................................................................... xxiv

Oracle9i の PL/SQL の新機能 ........................................................................................................................... xxvii

1 PL/SQL の概要の概要の概要の概要

PL/SQL のメリットのメリットのメリットのメリット ............................................................................................................................................... 1-2

SQL との緊密な統合 ...................................................................................................................................... 1-2

SQL のサポート .............................................................................................................................................. 1-2

高いパフォーマンス ....................................................................................................................................... 1-3

高い生産性 ....................................................................................................................................................... 1-4

完全な移植性 ................................................................................................................................................... 1-4

優れたセキュリティ ....................................................................................................................................... 1-5

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

PL/SQL の主な特長の主な特長の主な特長の主な特長 ............................................................................................................................................... 1-5

ブロック構造 ................................................................................................................................................... 1-6

変数と定数 ....................................................................................................................................................... 1-6

PL/SQL を使用した問合せの処理 ............................................................................................................... 1-8

i

Page 4: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 変数の宣言 ....................................................................................................................................... 1-8

制御構造 ........................................................................................................................................................... 1-9

再利用可能な PL/SQL コードの作成 ........................................................................................................ 1-12

データの抽象化 ............................................................................................................................................. 1-14

エラー処理 ..................................................................................................................................................... 1-16PL/SQL アーキテクチャアーキテクチャアーキテクチャアーキテクチャ ..................................................................................................................................... 1-16

Oracle データベース・サーバー ................................................................................................................ 1-17

Oracle のツール製品 .................................................................................................................................... 1-19

2 PL/SQL 言語の基礎言語の基礎言語の基礎言語の基礎

キャラクタ・セットキャラクタ・セットキャラクタ・セットキャラクタ・セット ............................................................................................................................................... 2-2

字句単位字句単位字句単位字句単位 ................................................................................................................................................................... 2-2

デリミタ ........................................................................................................................................................... 2-3

識別子 ............................................................................................................................................................... 2-4

リテラル ........................................................................................................................................................... 2-6

コメント ........................................................................................................................................................... 2-9宣言宣言宣言宣言 ......................................................................................................................................................................... 2-11

DEFAULT の使用 ......................................................................................................................................... 2-12

NOT NULL の使用 ....................................................................................................................................... 2-12

%TYPE 属性の使用 ...................................................................................................................................... 2-12

%ROWTYPE 属性の使用 ............................................................................................................................. 2-14

宣言の制限 ..................................................................................................................................................... 2-16PL/SQL のネーミング規則のネーミング規則のネーミング規則のネーミング規則 ................................................................................................................................. 2-16PL/SQL の識別子の有効範囲と可視性の識別子の有効範囲と可視性の識別子の有効範囲と可視性の識別子の有効範囲と可視性 ............................................................................................................. 2-19

変数への値の代入変数への値の代入変数への値の代入変数への値の代入 ................................................................................................................................................. 2-22

ブール値の代入 ............................................................................................................................................. 2-22

SQL 問合せ結果の PL/SQL 変数への代入 ............................................................................................... 2-23

PL/SQL の式および比較の式および比較の式および比較の式および比較 ..................................................................................................................................... 2-23

論理演算子 ..................................................................................................................................................... 2-25

ブール式 ......................................................................................................................................................... 2-29

CASE 式 ......................................................................................................................................................... 2-32

比較文と条件文での NULL の扱い ........................................................................................................... 2-34PL/SQL の組込みファンクションのまとめの組込みファンクションのまとめの組込みファンクションのまとめの組込みファンクションのまとめ ..................................................................................................... 2-38

ii

Page 5: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

3 PL/SQL のデータ型のデータ型のデータ型のデータ型

事前定義された事前定義された事前定義された事前定義された PL/SQL データ型の概要データ型の概要データ型の概要データ型の概要 .......................................................................................................... 3-2

PL/SQL の数値型 ........................................................................................................................................... 3-3

PL/SQL の文字型と文字列型 ....................................................................................................................... 3-6

PL/SQL の各国語キャラクタ・タイプ ..................................................................................................... 3-11

PL/SQL LOB 型 ............................................................................................................................................ 3-13

PL/SQL のブール型 ..................................................................................................................................... 3-15

PL/SQL の日付型、時刻型および時間隔型 ............................................................................................. 3-15

日時および時間隔の演算 ............................................................................................................................. 3-20

日付および時刻のサブタイプを使用する場合の切捨て問題の回避 ..................................................... 3-20PL/SQL サブタイプの概要サブタイプの概要サブタイプの概要サブタイプの概要 ................................................................................................................................. 3-21

サブタイプの定義 ......................................................................................................................................... 3-21

サブタイプの使用 ......................................................................................................................................... 3-22

PL/SQL データ型の変換データ型の変換データ型の変換データ型の変換 ..................................................................................................................................... 3-23

明示的な変換 ................................................................................................................................................. 3-23

暗黙的な変換 ................................................................................................................................................. 3-23

暗黙的変換と明示的変換の選択 ................................................................................................................. 3-25

DATE の値 ..................................................................................................................................................... 3-25

RAW および LONG RAW の値 ................................................................................................................. 3-26

4 PL/SQL の制御構造の使用の制御構造の使用の制御構造の使用の制御構造の使用

PL/SQL の制御構造の概要の制御構造の概要の制御構造の概要の制御構造の概要 ................................................................................................................................... 4-2条件テスト条件テスト条件テスト条件テスト : IF 文および文および文および文および CASE 文文文文 ...................................................................................................................... 4-2

IF-THEN 文の使用 ......................................................................................................................................... 4-2

IF-THEN-ELSE 文の使用 ............................................................................................................................... 4-3

IF-THEN-ELSEIF 文の使用 ........................................................................................................................... 4-4

CASE 文の使用 ............................................................................................................................................... 4-4

PL/SQL 条件文のガイドライン ................................................................................................................... 4-7ループの反復の制御ループの反復の制御ループの反復の制御ループの反復の制御 : LOOP 文と文と文と文と EXIT 文文文文 ........................................................................................................ 4-8

LOOP 文の使用 ............................................................................................................................................... 4-8

EXIT 文の使用 ................................................................................................................................................. 4-9

EXIT-WHEN 文の使用 .................................................................................................................................. 4-9

PL/SQL ループのラベル付け ..................................................................................................................... 4-10

WHILE-LOOP 文の使用 .............................................................................................................................. 4-10

FOR-LOOP 文の使用 ................................................................................................................................... 4-11

iii

Page 6: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

順次制御順次制御順次制御順次制御 : GOTO 文と文と文と文と NULL 文文文文 ....................................................................................................................... 4-15

GOTO 文の使用 ............................................................................................................................................ 4-16

NULL 文の使用 ............................................................................................................................................ 4-18

5 PL/SQL のコレクションおよびレコードの使用のコレクションおよびレコードの使用のコレクションおよびレコードの使用のコレクションおよびレコードの使用

コレクションコレクションコレクションコレクション ........................................................................................................................................................... 5-2

ネストした表 ................................................................................................................................................... 5-2

VARRAY .......................................................................................................................................................... 5-3

結合配列(索引付き表) ................................................................................................................................. 5-4

グローバリゼーション設定が結合配列の VARCHAR2 キーに与える影響 .......................................... 5-5使用する使用する使用する使用する PL/SQL コレクション型の選択コレクション型の選択コレクション型の選択コレクション型の選択 .......................................................................................................... 5-5

ネストした表と結合配列の選択 ................................................................................................................... 5-6

ネストした表と VARRAY との使い分け .................................................................................................... 5-6コレクション型の定義コレクション型の定義コレクション型の定義コレクション型の定義 ........................................................................................................................................... 5-7

PL/SQL コレクション型に相当する SQL の型の定義 ............................................................................. 5-9PL/SQL のコレクション変数の宣言のコレクション変数の宣言のコレクション変数の宣言のコレクション変数の宣言 ................................................................................................................. 5-10コレクションの初期化および参照コレクションの初期化および参照コレクションの初期化および参照コレクションの初期化および参照 ..................................................................................................................... 5-13

コレクション要素の参照 ............................................................................................................................. 5-16コレクションの代入コレクションの代入コレクションの代入コレクションの代入 ............................................................................................................................................. 5-17コレクションの比較コレクションの比較コレクションの比較コレクションの比較 ............................................................................................................................................. 5-20

SQL 文での文での文での文での PL/SQL コレクションの使用コレクションの使用コレクションの使用コレクションの使用 ....................................................................................................... 5-23

INSERT、UPDATE および SELECT 文での PL/SQL の VARRAY の使用 ........................................ 5-26

SQL での個々のコレクション要素の操作 ................................................................................................ 5-27マルチレベル・コレクションの使用マルチレベル・コレクションの使用マルチレベル・コレクションの使用マルチレベル・コレクションの使用 ................................................................................................................. 5-27

コレクション・メソッドの使用コレクション・メソッドの使用コレクション・メソッドの使用コレクション・メソッドの使用 ......................................................................................................................... 5-30

コレクション要素の存在のチェック(EXISTS メソッド) ..................................................................... 5-31

コレクション内の要素数のカウント(COUNT メソッド) ................................................................... 5-31

コレクションの 大サイズのチェック(LIMIT メソッド) .................................................................. 5-32

初または 後のコレクション要素の検索(FIRST メソッドと LAST メソッド) ........................... 5-32

コレクションの各要素のループ(PRIOR メソッドと NEXT メソッド) ............................................. 5-34

コレクションのサイズの拡大(EXTEND メソッド) ............................................................................. 5-35

コレクションのサイズの縮小(TRIM メソッド) ................................................................................... 5-36

コレクション要素の削除(DELETE メソッド) ...................................................................................... 5-38

コレクション・パラメータへのメソッドの適用 ..................................................................................... 5-39コレクション例外の回避コレクション例外の回避コレクション例外の回避コレクション例外の回避 ..................................................................................................................................... 5-39PL/SQL レコードレコードレコードレコード ................................................................................................................................................. 5-41

iv

Page 7: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードの定義と宣言レコードの定義と宣言レコードの定義と宣言レコードの定義と宣言 ......................................................................................................................................... 5-41

プロシージャのパラメータおよびファンクションの戻り値としてのレコードの使用 ..................... 5-43レコードへの値の代入レコードへの値の代入レコードへの値の代入レコードへの値の代入 ......................................................................................................................................... 5-44

レコードの比較 ............................................................................................................................................. 5-46

PL/SQL レコードのデータベースへの挿入 ............................................................................................. 5-46

PL/SQL レコード値を使用したデータベースの更新 ............................................................................. 5-47

レコードの挿入 / 更新に関する制約 ........................................................................................................ 5-49

レコードのコレクションへのデータの問合せ ......................................................................................... 5-49

6 PL/SQL でのでのでのでの SQL 操作の実行操作の実行操作の実行操作の実行

PL/SQL におけるにおけるにおけるにおける SQL サポートの概要サポートの概要サポートの概要サポートの概要 ............................................................................................................. 6-2

データ操作 ....................................................................................................................................................... 6-2

トランザクション制御 ................................................................................................................................... 6-2

SQL ファンクション ...................................................................................................................................... 6-3

SQL 疑似列 ...................................................................................................................................................... 6-3

SQL 演算子 ...................................................................................................................................................... 6-5PL/SQL でのでのでのでの DML 操作の実行(操作の実行(操作の実行(操作の実行(INSERT、、、、UPDATE およびおよびおよびおよび DELETE)))) .................................................... 6-6

暗黙カーソルの属性の概要 ........................................................................................................................... 6-7

SQL のののの INSERT 文および文および文および文および UPDATE 文での文での文での文での PL/SQL レコードの使用レコードの使用レコードの使用レコードの使用 ......................................................... 6-9PL/SQL での問合せの発行での問合せの発行での問合せの発行での問合せの発行 ................................................................................................................................... 6-9

1 行のみの選択 : SELECT INTO 文 ............................................................................................................ 6-10

複数行の選択 : BULK COLLECT 句 .......................................................................................................... 6-10

複数行のループ : カーソル FOR ループ .................................................................................................... 6-11

複雑な問合せの処理の実行 : 明示カーソル .............................................................................................. 6-11

PL/SQL を使用したデータの問合せを使用したデータの問合せを使用したデータの問合せを使用したデータの問合せ ................................................................................................................. 6-11

PL/SQL を使用したデータの問合せ : 暗黙カーソルの FOR ループ .................................................... 6-12

PL/SQL を使用したデータの問合せ : 明示カーソルの FOR ループ .................................................... 6-12

カーソル FOR ループ内の式の別名の定義 ............................................................................................... 6-13

明示カーソルの概要 ..................................................................................................................................... 6-14副問合せの使用副問合せの使用副問合せの使用副問合せの使用 ..................................................................................................................................................... 6-18

相関副問合せの使用相関副問合せの使用相関副問合せの使用相関副問合せの使用 ............................................................................................................................................. 6-19

メンテナンス可能な PL/SQL 問合せの作成 ............................................................................................ 6-20カーソル属性の使用カーソル属性の使用カーソル属性の使用カーソル属性の使用 ............................................................................................................................................. 6-21

明示カーソルの属性の概要 ......................................................................................................................... 6-21カーソル変数(カーソル変数(カーソル変数(カーソル変数(REF CURSOR)の使用)の使用)の使用)の使用 ........................................................................................................... 6-25

v

Page 8: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR) .................................................................................................................. 6-25

変数を使用する理由 ..................................................................................................................................... 6-25

REF CURSOR 型およびカーソル変数の宣言 ........................................................................................... 6-26

カーソル変数の制御 : OPEN-FOR、FETCH および CLOSE ................................................................. 6-28

ホスト・カーソル変数を PL/SQL に渡すときのネットワークの通信量の削減 ................................ 6-34

カーソル変数でのエラーの回避 ................................................................................................................. 6-34

カーソル変数の制限 ..................................................................................................................................... 6-35

カーソル式の使用カーソル式の使用カーソル式の使用カーソル式の使用 ................................................................................................................................................. 6-35

カーソル式の制限 ......................................................................................................................................... 6-36

カーソル式の例 ............................................................................................................................................. 6-36

カーソル副問合せを使用した REF CURSOR の構成 .............................................................................. 6-37

PL/SQL におけるトランザクション処理の概要におけるトランザクション処理の概要におけるトランザクション処理の概要におけるトランザクション処理の概要 ............................................................................................. 6-38

PL/SQL での COMMIT、SAVEPOINT および ROLLBACK の使用 .................................................. 6-38

Oracle による暗黙的なロールバックの実行方法 .................................................................................... 6-41

トランザクションの終了 ............................................................................................................................. 6-41

SET TRANSACTION を使用したトランザクション・プロパティの設定 .......................................... 6-41

デフォルトのロックの上書き ..................................................................................................................... 6-42

自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行 ............................................................................. 6-45

自律型トランザクションのメリット ......................................................................................................... 6-46

自律型トランザクションの定義 ................................................................................................................. 6-46

自律型トランザクションの制御 ................................................................................................................. 6-49

自律型トリガーの使用 ................................................................................................................................. 6-50

SQL からの自律型ファンクションのコール ............................................................................................ 6-51

7 システム固有の動的システム固有の動的システム固有の動的システム固有の動的 SQL を使用したを使用したを使用したを使用した SQL 操作の実行操作の実行操作の実行操作の実行

動的動的動的動的 SQL .................................................................................................................................................................. 7-2動的動的動的動的 SQL が必要になる場合が必要になる場合が必要になる場合が必要になる場合 ................................................................................................................................. 7-2

EXECUTE IMMEDIATE 文の使用文の使用文の使用文の使用 ..................................................................................................................... 7-3

動的 SQL 文字列におけるバインド変数のパラメータ・モードの指定 ................................................. 7-5動的動的動的動的 SQL を使用した動的問合せの構築を使用した動的問合せの構築を使用した動的問合せの構築を使用した動的問合せの構築 ............................................................................................................ 7-5

レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的 SQL の例の例の例の例 .................................................................... 7-6バルク動的バルク動的バルク動的バルク動的 SQL の使用の使用の使用の使用 ......................................................................................................................................... 7-8

動的 SQL とバルク SQL の使用 ................................................................................................................... 7-8

バルク動的バインドの例 ............................................................................................................................... 7-9

動的動的動的動的 SQL のガイドラインのガイドラインのガイドラインのガイドライン ................................................................................................................................... 7-10

vi

Page 9: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL でのセミコロンの使用または省略 ........................................................................................... 7-10

バインド変数を使用した動的 SQL のパフォーマンスの向上 ............................................................... 7-11

パラメータとしてのスキーマ・オブジェクト名の引渡し ..................................................................... 7-11

動的 SQL での重複するプレースホルダの使用 ....................................................................................... 7-12

動的 SQL でのカーソル属性の使用 ........................................................................................................... 7-12

動的 SQL への NULL の引渡し .................................................................................................................. 7-13

動的 SQL でのデータベース・リンクの使用 ........................................................................................... 7-13

動的 SQL での実行者権限の使用 ............................................................................................................... 7-14

動的 SQL での RESTRICT_REFERENCES プラグマの使用 .................................................................. 7-14

動的 SQL でのデッドロックの回避 ........................................................................................................... 7-15

USING 句の下位互換性 ............................................................................................................................... 7-15

8 PL/SQL のサブプログラムの使用のサブプログラムの使用のサブプログラムの使用のサブプログラムの使用

サブプログラムサブプログラムサブプログラムサブプログラム ....................................................................................................................................................... 8-2PL/SQL サブプログラムのメリットサブプログラムのメリットサブプログラムのメリットサブプログラムのメリット ................................................................................................................... 8-3

PL/SQL プロシージャプロシージャプロシージャプロシージャ ........................................................................................................................................... 8-3PL/SQL ファンクションファンクションファンクションファンクション ....................................................................................................................................... 8-4

RETURN 文の使用 ......................................................................................................................................... 8-6

ネストしたネストしたネストしたネストした PL/SQL サブプログラムの宣言サブプログラムの宣言サブプログラムの宣言サブプログラムの宣言 ...................................................................................................... 8-7PL/SQL サブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡し ........................................................................................... 8-7

サブプログラムの実パラメータと仮パラメータ ....................................................................................... 8-8

サブプログラムのパラメータの位置表記法、名前表記法または混合表記法 ....................................... 8-9

サブプログラムのパラメータのモードの指定 ......................................................................................... 8-10

サブプログラムのパラメータのデフォルト値の使用 ............................................................................. 8-12

サブプログラム名のオーバーロードサブプログラム名のオーバーロードサブプログラム名のオーバーロードサブプログラム名のオーバーロード ................................................................................................................. 8-12

数値型のオーバーロードのガイドライン ................................................................................................. 8-14

オーバーロードの制限 ................................................................................................................................. 8-15

サブプログラムのコールの解決方法サブプログラムのコールの解決方法サブプログラムのコールの解決方法サブプログラムのコールの解決方法 ................................................................................................................. 8-15

オーバーロードと継承の相互作用 ............................................................................................................. 8-18実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(AUTHID 句)句)句)句) ............................................................................................. 8-20

実行者権限のメリット ................................................................................................................................. 8-20

AUTHID 句によるサブプログラムの権限の指定 ................................................................................... 8-21

サブプログラム実行中の現行ユーザー ..................................................................................................... 8-21

実行者権限サブプログラムでの外部参照の解決 ..................................................................................... 8-22

実行者権限サブプログラムでのデフォルトの名前解決のオーバーライド ......................................... 8-22

vii

Page 10: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限サブプログラムに対する権限の付与 ..................................................................................... 8-23

実行者権限サブプログラムでのロールの使用 ......................................................................................... 8-24

実行者権限サブプログラムでのビューおよびデータベース・トリガーの使用 ................................. 8-24

実行者権限サブプログラムでのデータベース・リンクの使用 ............................................................. 8-25

実行者権限サブプログラムでのオブジェクト型の使用 ......................................................................... 8-25PL/SQL での再帰の使用での再帰の使用での再帰の使用での再帰の使用 ..................................................................................................................................... 8-27

再帰的サブプログラム ................................................................................................................................. 8-27

外部サブプログラムのコール外部サブプログラムのコール外部サブプログラムのコール外部サブプログラムのコール ............................................................................................................................. 8-27PL/SQL Server Pages((((PSP)を使用した動的)を使用した動的)を使用した動的)を使用した動的 Web ページの作成ページの作成ページの作成ページの作成 ............................................................. 8-29PL/SQL サブプログラムの副作用の制御サブプログラムの副作用の制御サブプログラムの副作用の制御サブプログラムの副作用の制御 ......................................................................................................... 8-29

サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解 ................................................................................. 8-30

9 PL/SQL パッケージの使用パッケージの使用パッケージの使用パッケージの使用

PL/SQL パッケージパッケージパッケージパッケージ ............................................................................................................................................... 9-2

PL/SQL パッケージの内容 ........................................................................................................................... 9-2

PL/SQL パッケージの例 ............................................................................................................................... 9-3PL/SQL パッケージのメリットパッケージのメリットパッケージのメリットパッケージのメリット ........................................................................................................................... 9-4

パッケージ仕様部の理解パッケージ仕様部の理解パッケージ仕様部の理解パッケージ仕様部の理解 ....................................................................................................................................... 9-5

パッケージの内容の参照 ............................................................................................................................... 9-6パッケージ本体の理解パッケージ本体の理解パッケージ本体の理解パッケージ本体の理解 ........................................................................................................................................... 9-7

パッケージ機能の例パッケージ機能の例パッケージ機能の例パッケージ機能の例 ............................................................................................................................................... 9-8パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目 ......................................................................................... 9-13パッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロード ............................................................................................. 9-13

パッケージパッケージパッケージパッケージ STANDARD によるによるによるによる PL/SQL 環境の定義環境の定義環境の定義環境の定義 ................................................................................... 9-14製品固有のパッケージの概要製品固有のパッケージの概要製品固有のパッケージの概要製品固有のパッケージの概要 ............................................................................................................................. 9-15

DBMS_ALERT パッケージ ......................................................................................................................... 9-15

DBMS_OUTPUT パッケージ ...................................................................................................................... 9-15

DBMS_PIPE パッケージ .............................................................................................................................. 9-16

UTL_FILE パッケージ ................................................................................................................................. 9-16

UTL_HTTP パッケージ ............................................................................................................................... 9-16

パッケージ作成のガイドラインパッケージ作成のガイドラインパッケージ作成のガイドラインパッケージ作成のガイドライン ......................................................................................................................... 9-17パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離 ................................................................................................. 9-17

10 PL/SQL エラーの処理エラーの処理エラーの処理エラーの処理

PL/SQL のランタイム・エラー処理の概要のランタイム・エラー処理の概要のランタイム・エラー処理の概要のランタイム・エラー処理の概要 ..................................................................................................... 10-2

PL/SQL エラーと例外の回避および処理のガイドライン ..................................................................... 10-3

viii

Page 11: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外のメリット例外のメリット例外のメリット例外のメリット ..................................................................................................................................... 10-4

事前定義の事前定義の事前定義の事前定義の PL/SQL 例外のまとめ例外のまとめ例外のまとめ例外のまとめ .................................................................................................................... 10-5独自の独自の独自の独自の PL/SQL 例外の定義例外の定義例外の定義例外の定義 ................................................................................................................................ 10-8

PL/SQL 例外の宣言 ..................................................................................................................................... 10-8

PL/SQL 例外の有効範囲規則 ..................................................................................................................... 10-8

PL/SQL 例外と番号の関連付け : EXCEPTION_INIT プラグマ ........................................................... 10-9

独自のエラー・メッセージの定義 : RAISE_APPLICATION_ERROR プロシージャ ..................... 10-10

事前定義の例外の再宣言 ........................................................................................................................... 10-11PL/SQL 例外の呼出し例外の呼出し例外の呼出し例外の呼出し ....................................................................................................................................... 10-12

RAISE 文を使用した例外の呼出し .......................................................................................................... 10-12

PL/SQL 例外の伝播例外の伝播例外の伝播例外の伝播 ........................................................................................................................................... 10-13PL/SQL 例外の再呼出し例外の再呼出し例外の再呼出し例外の再呼出し ................................................................................................................................... 10-16呼び出された呼び出された呼び出された呼び出された PL/SQL 例外の処理例外の処理例外の処理例外の処理 .................................................................................................................. 10-17

宣言の中で呼び出された例外の処理 ....................................................................................................... 10-18

ハンドラの中で呼び出された例外の処理 ............................................................................................... 10-18

例外ハンドラへの分岐と例外ハンドラからの分岐 ............................................................................... 10-18

エラー・コードとエラー・メッセージの取得 : SQLCODE および SQLERRM ............................... 10-19

未処理例外の捕捉 ....................................................................................................................................... 10-20PL/SQL エラーの処理のヒントエラーの処理のヒントエラーの処理のヒントエラーの処理のヒント ....................................................................................................................... 10-20

例外が呼び出された後に実行を続ける方法 ........................................................................................... 10-20

トランザクションの再試行 ....................................................................................................................... 10-21

ロケータ変数を使用した例外の位置の識別 ........................................................................................... 10-22PL/SQL のコンパイル時の警告の概要のコンパイル時の警告の概要のコンパイル時の警告の概要のコンパイル時の警告の概要 ........................................................................................................... 10-23

PL/SQL の警告カテゴリ ........................................................................................................................... 10-23

PL/SQL 警告メッセージの制御 ............................................................................................................... 10-24

DBMS_WARNING パッケージの使用 ................................................................................................... 10-24

11 PL/SQL アプリケーションのパフォーマンスのチューニングアプリケーションのパフォーマンスのチューニングアプリケーションのパフォーマンスのチューニングアプリケーションのパフォーマンスのチューニング

PL/SQL でプログラムを 適化する方法でプログラムを 適化する方法でプログラムを 適化する方法でプログラムを 適化する方法 ......................................................................................................... 11-2PL/SQL コードをチューニングする場合コードをチューニングする場合コードをチューニングする場合コードをチューニングする場合 ......................................................................................................... 11-2

PL/SQL のパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドライン ................................................................. 11-3

PL/SQL コードでの CPU オーバーヘッドの回避 .................................................................................. 11-3

PL/SQL コードでのメモリー・オーバーヘッドの回避 ......................................................................... 11-7

PL/SQL プログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレース ..................................................................................... 11-8

プロファイラ API の使用 : DBMS_PROFILER パッケージ ................................................................... 11-8

トレース API の使用 : DBMS_TRACE パッケージ ................................................................................. 11-9

ix

Page 12: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(文および問合せのループ・オーバーヘッドの削減(文および問合せのループ・オーバーヘッドの削減(文および問合せのループ・オーバーヘッドの削減(FORALL およびおよびおよびおよび BULK COLLECT)))) .......... 11-9

FORALL 文の使用 ...................................................................................................................................... 11-10

BULK COLLECT 句を使用した、問合せ結果のコレクションへの取出し ....................................... 11-19PL/SQL での計算集中型プログラムの記述での計算集中型プログラムの記述での計算集中型プログラムの記述での計算集中型プログラムの記述 ................................................................................................... 11-24

EXECUTE IMMEDIATE およびカーソル変数を使用した動的およびカーソル変数を使用した動的およびカーソル変数を使用した動的およびカーソル変数を使用した動的 SQL のチューニングのチューニングのチューニングのチューニング ........................... 11-25NOCOPY コンパイラ・ヒントを使用したコンパイラ・ヒントを使用したコンパイラ・ヒントを使用したコンパイラ・ヒントを使用した PL/SQL プロシージャ・コールのチューニングプロシージャ・コールのチューニングプロシージャ・コールのチューニングプロシージャ・コールのチューニング ............... 11-26

NOCOPY の制限 ........................................................................................................................................ 11-27

システム固有の実行のためのシステム固有の実行のためのシステム固有の実行のためのシステム固有の実行のための PL/SQL コードのコンパイルコードのコンパイルコードのコンパイルコードのコンパイル ...................................................................... 11-28テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定 ........................................................................... 11-36

テーブル・ファンクションの概要 ........................................................................................................... 11-36

変換へのパイプライン・テーブル・ファンクションの使用 ............................................................... 11-38

パイプライン・テーブル・ファンクションの記述 ............................................................................... 11-40

テーブル・ファンクションからの結果の戻し ....................................................................................... 11-40

PL/SQL テーブル・ファンクション間のデータのパイプライン ....................................................... 11-41

テーブル・ファンクションの問合せ ....................................................................................................... 11-42

テーブル・ファンクションに対する複数コールの 適化 ................................................................... 11-42

テーブル・ファンクションの結果からのフェッチ ............................................................................... 11-42

カーソル変数によるデータの引渡し ....................................................................................................... 11-43

テーブル・ファンクション内での DML 操作の実行 ........................................................................... 11-45

テーブル・ファンクションへの DML 操作の実行 ............................................................................... 11-46

テーブル・ファンクションの例外処理 ................................................................................................... 11-46

12 PL/SQL のオブジェクト型の使用のオブジェクト型の使用のオブジェクト型の使用のオブジェクト型の使用

PL/SQL のオブジェクト型の概要のオブジェクト型の概要のオブジェクト型の概要のオブジェクト型の概要 ..................................................................................................................... 12-2

オブジェクト型オブジェクト型オブジェクト型オブジェクト型 ..................................................................................................................................................... 12-2オブジェクト型を使用する理由オブジェクト型を使用する理由オブジェクト型を使用する理由オブジェクト型を使用する理由 ......................................................................................................................... 12-4オブジェクト型の構造オブジェクト型の構造オブジェクト型の構造オブジェクト型の構造 ......................................................................................................................................... 12-5

オブジェクト型の構成要素オブジェクト型の構成要素オブジェクト型の構成要素オブジェクト型の構成要素 ................................................................................................................................. 12-6

オブジェクト型のメソッドに使用できる言語 ......................................................................................... 12-8

オブジェクト型による SELF パラメータの処理方法 ............................................................................. 12-8

オーバーロード ............................................................................................................................................. 12-9

既存のオブジェクト型の属性およびメソッドの変更(型の発展) ..................................................... 12-12オブジェクト型の定義オブジェクト型の定義オブジェクト型の定義オブジェクト型の定義 ....................................................................................................................................... 12-13

PL/SQL の型の継承の概要 ....................................................................................................................... 12-13オブジェクトの宣言と初期化オブジェクトの宣言と初期化オブジェクトの宣言と初期化オブジェクトの宣言と初期化 ........................................................................................................................... 12-15

オブジェクトの宣言 ................................................................................................................................... 12-15

x

Page 13: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクトの初期化 ............................................................................................................................... 12-16

PL/SQL による未初期化オブジェクトの処理 ....................................................................................... 12-16オブジェクト属性へのアクセスオブジェクト属性へのアクセスオブジェクト属性へのアクセスオブジェクト属性へのアクセス ....................................................................................................................... 12-17オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義 ........................................................................................................... 12-18

オブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコール ....................................................................................................... 12-19オブジェクト・メソッドのコールオブジェクト・メソッドのコールオブジェクト・メソッドのコールオブジェクト・メソッドのコール ................................................................................................................... 12-20REF 修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有 .......................................................................................................... 12-21

先送り型定義 ............................................................................................................................................... 12-22SQL を使用したオブジェクトの操作を使用したオブジェクトの操作を使用したオブジェクトの操作を使用したオブジェクトの操作 ............................................................................................................. 12-23

オブジェクトの選択 ................................................................................................................................... 12-24

オブジェクトの挿入 ................................................................................................................................... 12-28

オブジェクトの更新 ................................................................................................................................... 12-30

オブジェクトの削除 ................................................................................................................................... 12-30

13 PL/SQL の言語要素の言語要素の言語要素の言語要素

代入文代入文代入文代入文 ..................................................................................................................................................................... 13-4AUTONOMOUS_TRANSACTION プラグマプラグマプラグマプラグマ ............................................................................................... 13-8

ブロックブロックブロックブロック ............................................................................................................................................................... 13-11CASE 文文文文 ............................................................................................................................................................... 13-18CLOSE 文文文文 ............................................................................................................................................................ 13-21

コレクション・メソッドコレクション・メソッドコレクション・メソッドコレクション・メソッド ................................................................................................................................... 13-23コレクションコレクションコレクションコレクション ....................................................................................................................................................... 13-29コメントコメントコメントコメント ............................................................................................................................................................... 13-35

COMMIT 文文文文 ....................................................................................................................................................... 13-37定数と変数定数と変数定数と変数定数と変数 ........................................................................................................................................................... 13-39カーソル属性カーソル属性カーソル属性カーソル属性 ....................................................................................................................................................... 13-43

カーソル変数カーソル変数カーソル変数カーソル変数 ....................................................................................................................................................... 13-47カーソルカーソルカーソルカーソル ............................................................................................................................................................... 13-53DELETE 文文文文 .......................................................................................................................................................... 13-57

EXCEPTION_INIT プラグマプラグマプラグマプラグマ ........................................................................................................................... 13-60例外例外例外例外 ....................................................................................................................................................................... 13-62EXECUTE IMMEDIATE 文文文文 ............................................................................................................................. 13-65

EXIT 文文文文 ................................................................................................................................................................ 13-69式式式式 ........................................................................................................................................................................... 13-71FETCH 文文文文 ............................................................................................................................................................ 13-81

FORALL 文文文文 ......................................................................................................................................................... 13-86ファンクションファンクションファンクションファンクション ................................................................................................................................................... 13-90

xi

Page 14: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

GOTO 文文文文 ............................................................................................................................................................. 13-95

IF 文文文文 ...................................................................................................................................................................... 13-97INSERT 文文文文 ........................................................................................................................................................... 13-99リテラルリテラルリテラルリテラル ............................................................................................................................................................ 13-102

LOCK TABLE 文文文文 ............................................................................................................................................. 13-105LOOP 文文文文 ........................................................................................................................................................... 13-107MERGE 文文文文 ........................................................................................................................................................ 13-113

NULL 文文文文 ........................................................................................................................................................... 13-114オブジェクト型オブジェクト型オブジェクト型オブジェクト型 ................................................................................................................................................ 13-115OPEN 文文文文 ........................................................................................................................................................... 13-124

OPEN-FOR 文文文文 ................................................................................................................................................. 13-126OPEN-FOR-USING 文文文文 .................................................................................................................................. 13-129パッケージパッケージパッケージパッケージ ........................................................................................................................................................ 13-132

プロシージャプロシージャプロシージャプロシージャ .................................................................................................................................................... 13-138RAISE 文文文文 .......................................................................................................................................................... 13-143レコードレコードレコードレコード ............................................................................................................................................................ 13-145

RESTRICT_REFERENCES プラグマプラグマプラグマプラグマ .......................................................................................................... 13-150RETURN 文文文文 ..................................................................................................................................................... 13-153ROLLBACK 文文文文 ................................................................................................................................................ 13-155

%ROWTYPE 属性属性属性属性 ........................................................................................................................................... 13-157SAVEPOINT 文文文文 ............................................................................................................................................... 13-159

SCN_TO_TIMESTAMP ファンクションファンクションファンクションファンクション ................................................................................................... 13-160SELECT INTO 文文文文 ............................................................................................................................................ 13-162SERIALLY_REUSABLE プラグマプラグマプラグマプラグマ ................................................................................................................ 13-167

SET TRANSACTION 文文文文 ............................................................................................................................... 13-169SQL カーソルカーソルカーソルカーソル ................................................................................................................................................... 13-172SQLCODE ファンクションファンクションファンクションファンクション ........................................................................................................................... 13-177

SQLERRM ファンクションファンクションファンクションファンクション .......................................................................................................................... 13-179TIMESTAMP_TO_SCN ファンクションファンクションファンクションファンクション ................................................................................................... 13-181%TYPE 属性属性属性属性 ..................................................................................................................................................... 13-182

UPDATE 文文文文 ...................................................................................................................................................... 13-185

A PL/SQL のサンプル・プログラムのサンプル・プログラムのサンプル・プログラムのサンプル・プログラム

PL/SQL のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所 ................................................................................................... A-2

学習のガイドライン学習のガイドライン学習のガイドライン学習のガイドライン ............................................................................................................................................... A-2

xii

Page 15: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

B PL/SQL におけるにおけるにおけるにおける CHAR とととと VARCHAR2 の意味の意味の意味の意味

文字値の代入文字値の代入文字値の代入文字値の代入 ........................................................................................................................................................... B-2文字値の比較文字値の比較文字値の比較文字値の比較 ........................................................................................................................................................... B-2

文字値の挿入文字値の挿入文字値の挿入文字値の挿入 ........................................................................................................................................................... B-3文字値の選択文字値の選択文字値の選択文字値の選択 ........................................................................................................................................................... B-4

C PL/SQL ラップ・ユーティリティを使用したソース・コードの不明瞭化ラップ・ユーティリティを使用したソース・コードの不明瞭化ラップ・ユーティリティを使用したソース・コードの不明瞭化ラップ・ユーティリティを使用したソース・コードの不明瞭化

PL/SQL プロシージャのラッピングのメリットプロシージャのラッピングのメリットプロシージャのラッピングのメリットプロシージャのラッピングのメリット .............................................................................................. C-2PL/SQL ラップ・ユーティリティの実行ラップ・ユーティリティの実行ラップ・ユーティリティの実行ラップ・ユーティリティの実行 .......................................................................................................... C-2

PL/SQL ラップ・ユーティリティの入力ファイルと出力ファイル ...................................................... C-3

PL/SQL ラップ・ユーティリティの制限ラップ・ユーティリティの制限ラップ・ユーティリティの制限ラップ・ユーティリティの制限 .......................................................................................................... C-4

D PL/SQL での識別子名の解決での識別子名の解決での識別子名の解決での識別子名の解決

名前解決名前解決名前解決名前解決 .................................................................................................................................................................. D-2

修飾名およびドット表記法の例修飾名およびドット表記法の例修飾名およびドット表記法の例修飾名およびドット表記法の例 .......................................................................................................................... D-3SQL とととと PL/SQL の名前解決の相違点の名前解決の相違点の名前解決の相違点の名前解決の相違点 ................................................................................................................ D-4取得の理解取得の理解取得の理解取得の理解 .............................................................................................................................................................. D-4

内部取得 .......................................................................................................................................................... D-5

同一有効範囲の取得 ...................................................................................................................................... D-6

外部取得 .......................................................................................................................................................... D-6

DML 文の内部取得の回避文の内部取得の回避文の内部取得の回避文の内部取得の回避 ................................................................................................................................... D-6オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾 .......................................................................................... D-6パラメータを持たないサブプログラムとメソッドのコールパラメータを持たないサブプログラムとメソッドのコールパラメータを持たないサブプログラムとメソッドのコールパラメータを持たないサブプログラムとメソッドのコール .......................................................................... D-7

SQL とととと PL/SQL の名前解決の比較の名前解決の比較の名前解決の比較の名前解決の比較 .................................................................................................................... D-8

E PL/SQL のプログラム上の制限のプログラム上の制限のプログラム上の制限のプログラム上の制限

F PL/SQL の予約語のリストの予約語のリストの予約語のリストの予約語のリスト

G PL/SQL に関するに関するに関するに関する FAQ

PL/SQL でのバインド変数の使用でのバインド変数の使用でのバインド変数の使用でのバインド変数の使用 ...................................................................................................................... G-2

動的動的動的動的 SQL でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略 ................................................................................................... G-2PL/SQL での正規表現の使用での正規表現の使用での正規表現の使用での正規表現の使用 .............................................................................................................................. G-2PL/SQL 例外の後の継続例外の後の継続例外の後の継続例外の後の継続 ...................................................................................................................................... G-3

PL/SQL でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型 .......................................................................................... G-3

xiii

Page 16: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL からからからから Java またはまたはまたはまたは Visual Basic((((VB)への結果セットの引渡し)への結果セットの引渡し)への結果セットの引渡し)への結果セットの引渡し .................................................... G-3

PL/SQL のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定 .............................................................................. G-3PL/SQL でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用 .............................................................................. G-4PL/SQL プロシージャの作成プロシージャの作成プロシージャの作成プロシージャの作成 .............................................................................................................................. G-4

PL/SQL を使用したデータの入力または出力を使用したデータの入力または出力を使用したデータの入力または出力を使用したデータの入力または出力 .................................................................................................. G-5大大大大 / 小文字を区別しない問合せの実行小文字を区別しない問合せの実行小文字を区別しない問合せの実行小文字を区別しない問合せの実行 ............................................................................................................... G-6

索引索引索引索引

xiv

Page 17: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

はじめにはじめにはじめにはじめに

このマニュアルでは、PL/SQL 言語の概念を説明し、PL/SQL 言語の様々な機能を使用する方法を、例を示して説明します。

ここでは、次の項目について説明します。

� 対象読者

� このマニュアルの構成

� 関連ドキュメント

� 表記規則

� サンプル・データベース表

� 構文図の読み方

xv

Page 18: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

対象読者対象読者対象読者対象読者オラクル社の PL/SQL は、SQL を手続き型言語として機能拡張した、上級の第 4 世代プログラミング言語です。PL/SQL は、データのカプセル化、オーバーロード、コレクション型、例外処理、情報隠ぺいなどのソフトウェア・エンジニアリング機能を提供します。またPL/SQL は、SQL および Oracle データベースと緊密に統合され、短期間でのプロトタイプ作成およびプログラム開発をサポートします。

このマニュアルは、Oracle の PL/SQL ベースのアプリケーション開発者を対象としています。また、プログラマ、システム・アナリスト、プロジェクト・マネージャ、データベース管理者およびデータベース操作を自動化する必要があるユーザーも対象にしています。他の言語でアプリケーションを開発する開発者も、一部を PL/SQL で記述した混合言語アプリケーションを開発できます。

このマニュアルを効果的に使用するには、Oracle データベース、SQL 言語、およびIF-THEN比較、ループ、プロシージャ、ファンクションなどの基本的なプログラム構造体の実用的な知識が必要です。

このマニュアルの構成このマニュアルの構成このマニュアルの構成このマニュアルの構成このマニュアルの構成は、次のとおりです。

PL/SQL を使用する前にを使用する前にを使用する前にを使用する前に

第 1 章「PL/SQL の概要」

この章では、PL/SQL の主な機能およびメリットについて説明します。PL/SQL の基本概念を説明し、代表的な PL/SQL プログラムの形式を示します。

第 2 章「PL/SQL 言語の基礎」

この章では、PL/SQL の詳細(字句単位、スカラー・データ型、ユーザー定義のサブタイプ、データ変換、式、代入、ブロック構造、宣言および有効範囲)について説明します。

第 3 章「PL/SQL のデータ型」

この章では、整数、浮動小数点、文字、ブール、日付、コレクション、参照、LOB など、PL/SQL の事前定義のデータ型について説明します。また、ユーザー定義のサブタイプおよびデータ変換についても説明します。

第 4 章「PL/SQL の制御構造の使用」

この章では、PL/SQL プログラムの実行フローを制御する方法を示します。IF-THEN-ELSE、CASE、WHILE-LOOPなどの制御構造を使用した条件制御、反復制御および順次制御について説明します。

xvi

Page 19: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

第 5 章「PL/SQL のコレクションおよびレコードの使用」

この章では、コンポジット・データ型である TABLE、VARRAYおよび RECORDについて説明します。データのコレクション全体および様々な型のグループ・データを参照および操作する方法を説明します。

PL/SQL を使用したデータベースのプログラミングを使用したデータベースのプログラミングを使用したデータベースのプログラミングを使用したデータベースのプログラミング

第 6 章「PL/SQL での SQL 操作の実行」

この章では、Oracle データを操作する SQL コマンド、ファンクションおよび演算子がPL/SQL でどのようにサポートされているのかを示します。また、問合せおよびトランザクションを処理する方法も示します。

第 7 章「システム固有の動的 SQL を使用した SQL 操作の実行」

この章では、実行時に SQL 文および SQL 問合せを構築する方法を示します。

PL/SQL を使用したソフトウェア・エンジニアリングを使用したソフトウェア・エンジニアリングを使用したソフトウェア・エンジニアリングを使用したソフトウェア・エンジニアリング第 8 章「PL/SQL のサブプログラムの使用」

この章では、プロシージャまたはファンクションを記述およびコールする方法を示します。パラメータ、オーバーロード、サブプログラムの様々な権限モデルなどの関連トピックについて説明します。

第 9 章「PL/SQL パッケージの使用」

この章では、関連する PL/SQL の型、項目およびサブプログラムを 1 つのパッケージにまとめる方法を示します。パッケージでは、多くのアプリケーションで再利用できるApplication Program Interface(API)が定義されます。

第 10 章「PL/SQL エラーの処理」

この章では、例外およびハンドラを使用して PL/SQL エラーを検出および処理する方法を示します。

第 11 章「PL/SQL アプリケーションのパフォーマンスのチューニング」

この章では、PL/SQL ベースのアプリケーションのパフォーマンスを向上させる方法を示します。

第 12 章「PL/SQL のオブジェクト型の使用」

この章では、オブジェクト型ベースのオブジェクト指向プログラミングの概要を示します。PL/SQL を使用してオブジェクト・メソッドを記述したり、オブジェクトを操作する方法について説明します。

xvii

Page 20: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 言語のリファレンス言語のリファレンス言語のリファレンス言語のリファレンス第 13 章「PL/SQL の言語要素」

この章では、文の構文、パラメータおよび他の PL/SQL 言語要素を示します。また、使用上の注意および簡単な例も示します。

付録付録付録付録

付録 A「PL/SQL のサンプル・プログラム」

この付録では、独自のプログラムを作成するうえで参考になる PL/SQL プログラムの参照先を示します。サンプル・プログラムには重要な概念や機能が盛り込まれています。

付録 B「PL/SQL における CHAR と VARCHAR2 の意味」

この付録では、ベース型 CHARと VARCHAR2のわずかではあるが、重要な意味上の相違点を説明します。

付録 C「PL/SQL ラップ・ユーティリティを使用したソース・コードの不明瞭化」

この付録では、ラップ・ユーティリティを実行する方法を示します。ラップ・ユーティリティは、ソース・コードを隠したまま PL/SQL アプリケーションを配布できるようにするスタンドアロン・プログラミング・ユーティリティです。

付録 D「PL/SQL での識別子名の解決」

この付録では、潜在的に意味の曖昧なプロシージャ文および SQL 文で、名前への参照をPL/SQL がどのように解決するかについて説明します。

付録 E「PL/SQL のプログラム上の制限」

この付録では、PL/SQL によって課されるコンパイル時および実行時の制限について説明します。

付録 F「PL/SQL の予約語のリスト」

この付録では、PL/SQL で使用するために予約されている予約語のリストを示します。

付録 G「PL/SQL に関する FAQ」

この付録では、PL/SQL でよくある質問とその回答を示します。

xviii

Page 21: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

関連ドキュメント関連ドキュメント関連ドキュメント関連ドキュメント詳細は、次の Oracle ドキュメントを参照してください。

PL/SQL プログラミングの様々な側面、特にトリガーとストアド・プロシージャの詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

PL/SQL 機能と SQL 機能の両方を使用するオブジェクト指向のプログラミングの詳細は、『Oracle Database アプリケーション開発者ガイド - オブジェクト・リレーショナル機能』を参照してください。

ラージ・オブジェクト(LOB)を使用したプログラミングについては、『Oracle Database アプリケーション開発者ガイド - ラージ・オブジェクト』を参照してください。

SQL については、『Oracle Database SQL リファレンス』および『Oracle Database 管理者ガイド』を参照してください。Oracle の基本概念については、『Oracle Database 概要』を参照してください。

リリース・ノート、インストール関連ドキュメント、ホワイト・ペーパーまたはその他の関連ドキュメントは、OTN-J(Oracle Technology Network Japan)から、無償でダウンロードできます。OTN-J を使用するには、オンラインでの登録が必要です。登録は、次の Web サイトから無償で行えます。

http://otn.oracle.co.jp/membership/

すでに OTN-J のユーザー名およびパスワードを取得している場合は、次の URL で OTN-J Web サイトのドキュメントのセクションに直接接続できます。

http://otn.oracle.co.jp/document/

表記規則表記規則表記規則表記規則この項では、このマニュアルの本文およびコード例で使用される表記規則について説明します。この項の内容は次のとおりです。

� 本文の表記規則

� コード例の表記規則

xix

Page 22: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

本文の表記規則本文の表記規則本文の表記規則本文の表記規則本文では、特定の項目が一目でわかるように、次の表記規則を使用します。次の表に、その規則と使用例を示します。

規則規則規則規則 意味意味意味意味 例例例例

太字太字太字太字 太字は、本文中で定義されている用語および用語集に記載されている用語を示します。

この句を指定すると、索引構成表索引構成表索引構成表索引構成表が作成されます。

固定幅フォントの大文字

固定幅フォントの大文字は、システム指定の要素を示します。このような要素には、パラメータ、権限、データ型、Recovery Manager キーワード、SQL キーワード、

SQL*Plus またはユーティリティ・コマン

ド、パッケージおよびメソッドがあります。また、システム指定の列名、データベース・オブジェクト、データベース構造、ユーザー名およびロールも含まれます。

NUMBER列に対してのみ、この句を指定できます。

BACKUPコマンドを使用して、データベースの

バックアップを作成できます。

USER_TABLESデータ・ディクショナリ・ビュー

内の TABLE_NAME列を問い合せます。

DBMS_STATS.GENERATE_STATSプロシージャを

使用します。

固定幅フォントの小文字

固定幅フォントの小文字は、実行可能ファイル、ファイル名、ディレクトリ名およびユーザーが指定する要素のサンプルを示します。このような要素には、コンピュータ名およびデータベース名、ネット・サービス名および接続識別子があります。また、ユーザーが指定するデータベース・オブジェクトとデータベース構造、列名、パッケージとクラス、ユーザー名とロール、プログラム・ユニットおよびパラメータ値も含まれます。

sqlplusと入力して、SQL*Plus をオープンしま

す。

パスワードは、orapwdファイルで指定します。

/disk1/oracle/dbsディレクトリ内のデータ・

ファイルおよび制御ファイルのバックアップを作成します。

hr.departments表には、department_id、department_nameおよび location_id列があ

ります。

QUERY_REWRITE_ENABLED初期化パラメータを

trueに設定します。

oeユーザーとして接続します。

注意注意注意注意 : プログラム要素には、大文字と小文

字を組み合せて使用するものもあります。これらの要素は、記載されているとおりに入力してください。

JRepUtilクラスが次のメソッドを実装します。

固定幅フォントの小文字のイタリック

固定幅フォントの小文字のイタリックは、プレースホルダまたは変数を示します。

parallel_clauseを指定できます。

Uold_release.SQLを実行します。ここで、

old_releaseとはアップグレード前にインス

トールしたリリースを示します。

xx

Page 23: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コード例の表記規則コード例の表記規則コード例の表記規則コード例の表記規則コード例は、SQL、PL/SQL、SQL*Plus または他のコマンドライン文の例です。次のように固定幅フォントで表示され、通常のテキストと区別されます。

SELECT username FROM dba_users WHERE username = 'MIGRATE';

次の表に、コード例で使用される表記規則とその使用例を示します。

規則規則規則規則 意味意味意味意味 例例例例

[ ] 大カッコは、カッコ内の項目を任意に選択することを表します。大カッコは、入力しないでください。

DECIMAL (digits [ , precision ])

{ } 中カッコは、カッコ内の項目のうち、1 つが

必須であることを表します。中カッコは、入力しないでください。

{ENABLE | DISABLE}

| 縦線は、大カッコまたは中カッコ内の複数の選択項目の区切りに使用します。項目のうちの 1 つを入力します。縦線は、入力し

ないでください。

{ENABLE | DISABLE}

[COMPRESS | NOCOMPRESS]

... 水平の省略記号は、次のいずれかを示します。

� 例に直接関連しないコードの一部が省略されている。

� コードの一部を繰り返すことができる。

CREATE TABLE ... AS subquery;

SELECT col1, col2, ... , coln FROM employees;

. . .

垂直の省略記号は、例に直接関連しない複数の行が省略されていることを示します。

その他の記号 大カッコ、中カッコ、縦線および省略記号以外の記号は、記載されているとおりに入力する必要があります。

acctbal NUMBER(11,2);

acct CONSTANT NUMBER(4) := 3;

イタリック体 イタリック体は、特定の値を指定する必要があるプレースホルダや変数を示します。

CONNECT SYSTEM/system_password

DB_NAME = database_name

大文字 大文字は、システム指定の要素を示します。これらの要素は、ユーザー定義の要素と区別するために大文字で示されます。大カッコ内にないかぎり、表示されているとおりの順序および綴りで入力します。ただし、大 / 小文字が区別されないため、小文字で

も入力できます。

SELECT last_name, employee_id FROM employees;

SELECT * FROM USER_TABLES;

DROP TABLE hr.employees;

xxi

Page 24: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サンプル・データベース表サンプル・データベース表サンプル・データベース表サンプル・データベース表このマニュアルのいくつかのプログラミング例では、サンプル・データベースの HRスキーマの表と他のオブジェクトを使用しています。これらの表(EMPLOYEESや DEPARTMENTSなど)は、以前のリリースで使用していた EMPおよび DEPT表より広範囲かつ現実的です。

構文図の読み方構文図の読み方構文図の読み方構文図の読み方PL/SQL 文の構文は、構文図を左から右、上から下の順に読んでください。

この図は、バッカス正規形(BNF)の結果を表しています。この図では、四角形の中はキーボード、円の中はデリミタ、楕円の中は識別子です。

各図は、構文の要素を定義しています。図を通るパスは、それぞれがその要素のフォームとして考えられるものを表しています。矢印の向きに進んでください。線がループ状になっている場合は、そのループ内の要素を繰り返すことができます。

小文字 小文字は、ユーザー指定のプログラム要素を示します。たとえば、表名、列名またはファイル名などです。

注意注意注意注意 : プログラム要素には、大文字と小文

字を組み合せて使用するものもあります。これらの要素は、記載されているとおりに入力してください。

SELECT last_name, employee_id FROM employees;

sqlplus hr/hr

CREATE USER mjones IDENTIFIED BY ty3MU9;

-- 2 連続ハイフンは、その位置から行の終わり

までがコメントであることを示します。

--

/* */ スラッシュ - アスタリスクとアスタリスク - スラッシュは、複数行にまたがるコメン

トを区切ります。

/* */

規則規則規則規則 意味意味意味意味 例例例例

xxii

Page 25: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の新機能の新機能の新機能の新機能

ここでは、PL/SQL 10g リリース 1(10.1)の新機能について説明し、追加情報の参照先を示します。

次の PL/SQL の新機能について説明します。

� Oracle Database 10g の PL/SQL の新機能

� Oracle9i の PL/SQL の新機能

xxiii

Page 26: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

Oracle Database 10g のののの PL/SQL の新機能の新機能の新機能の新機能

リリースリリースリリースリリース 1((((10.1))))パフォーマンスの向上パフォーマンスの向上パフォーマンスの向上パフォーマンスの向上

PL/SQL のパフォーマンスは全体的に向上しています。ほとんどのパフォーマンスは自動的に向上し、何もする必要はありません。

PL/SQL コードのグローバル 適化は、PLSQL_OPTIMIZE_LEVEL初期化パラメータで制御されます。デフォルトの 適化レベルを使用すると、様々な PL/SQL 操作のパフォーマンスが向上します。ほとんどのユーザーは、デフォルトの 適化レベルを変更する必要がありません。

具体的には、整数パフォーマンスの向上、式値の再利用、コードの分岐の単純化、一部のライブラリ・コールのパフォーマンスの向上およびデッド・コードの排除が実現されています。

新しいデータ型 BINARY_FLOATおよび BINARY_DOUBLEを使用すると、科学的データの処理など、大量の演算を行うアプリケーションのパフォーマンスが向上します。

設定する初期化パラメータ数の減少、必要なコンパイラ構成の削減、データベースに格納されたオブジェクト・コード、および Oracle Real Application Clusters 環境との互換性によって、PL/SQL のネイティブ・コンパイルがより統合され、簡単になっています。

FORALL文を使用すると、削除された要素を含む結合配列およびネストした表を処理できます。このパフォーマンス構成を以前より多くの場面で使用でき、これによって 1 つのコレクションから別のコレクションに要素をコピーする必要がなくなります。

PL/SQL のネイティブ・コンパイルの拡張のネイティブ・コンパイルの拡張のネイティブ・コンパイルの拡張のネイティブ・コンパイルの拡張

この機能では、必要な設定およびメンテナンスが削減されています。

パッケージ本体とその仕様部は、同じネイティブ・コンパイル設定でコンパイルする必要がありません。たとえば、パッケージ本体をネイティブにコンパイルしてパッケージ仕様部を解釈したり、逆に本体を解釈して仕様部をネイティブにコンパイルできます。

ネイティブにコンパイルされたサブプログラムはデータベースに格納され、対応する共有ライブラリは必要に応じて自動的に抽出されます。共有ライブラリのバックアップ、古い共有ライブラリのクリーンアップ、または共有ライブラリが誤って削除された場合に発生する状況を考慮する必要はありません。

ネイティブ・コンパイル用の初期化パラメータおよびコマンドの設定が簡略化されています。必要なパラメータは PLSQL_NATIVE_LIBRARY_DIRのみです。コンパイラ、リンカーおよび make ユーティリティに関連するパラメータは廃止されています。コンパイルは、Make ファイルではなく、コマンド・ファイルによって制御されます。このコマンド・ファイルには、コンパイルおよびリンク用のコマンドとオプションが示されます。ネイティブ・コンパイル中に発生したエラーは、SQL*Plus コマンド SHOW ERRORSを使用して、USER_ERRORSディレクトリ・ビューに表示できます。

xxiv

Page 27: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ネイティブ・コンパイルは、PLSQL_COMPILER_FLAGSパラメータの 1 つのオプション(廃止)ではなく、専用の PLSQL_CODE_TYPE初期化パラメータで有効または無効にできます。

非連続索引の非連続索引の非連続索引の非連続索引の FORALL サポートサポートサポートサポート

FORALL文に INDICES OFおよび VALUES OF句を指定して、非連続索引値を反復できます。たとえば、ネストした表から要素を削除した後でも、FORALL文でそのネストした表を使用できます。

新しい新しい新しい新しい IEEE 浮動小数点型浮動小数点型浮動小数点型浮動小数点型

新しいデータ型 BINARY_FLOATおよび BINARY_DOUBLEは、IEEE 754 形式で浮動小数点数を表します。これらの型は、浮動小数点に IEEE 754 標準が使用される他のプログラムおよび言語とデータを交換する、科学的な計算に役立ちます。多くのコンピュータ・システムがシステム固有のプロセッサ命令を介して IEEE 754 浮動小数点の操作をサポートするため、これらの型は浮動小数点データを伴う集中的な計算に効果的です。

これらの型は、1.0fや 3.141dなどの数値リテラル、平方根や剰余などの算術演算、例外処理、および非数値(NaN)や無限大などの特殊な値をサポートします。

サブプログラムのオーバーロードの規則が拡張されており、PLS_INTEGER、NUMBER、BINARY_FLOATおよび BINARY_DOUBLEパラメータを操作する 1 つのファンクションの様々なバージョンを使用して数学ライブラリを記述できます。

オーバーロードの改善オーバーロードの改善オーバーロードの改善オーバーロードの改善

様々な数値引数を受け入れるサブプログラムをオーバーロードして、様々なデータ型に特化した各サブプログラムのバージョンを使用して、数学ライブラリを記述できます。

参照参照参照参照 :

� 11-28 ページの「システム固有の実行のための PL/SQL コードのコンパイル」

参照参照参照参照 :

� 11-10 ページの「FORALL 文の使用」

参照参照参照参照 :

� 3-3 ページの「PL/SQL の数値型」

参照参照参照参照 :

� 8-14 ページの「数値型のオーバーロードのガイドライン」

xxv

Page 28: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ネストした表の拡張ネストした表の拡張ネストした表の拡張ネストした表の拡張

PL/SQL に定義されたネストした表には、以前より多くの操作を実行できます。ネストした表が同じかどうかの比較、要素がネストした表のメンバーであるかどうかのテスト、1 つのネストした表が別のネストした表のサブセットであるかどうかのテスト、和集合や共通集合などの集合操作の実行など、様々な操作を行うことができます。

コンパイル時の警告コンパイル時の警告コンパイル時の警告コンパイル時の警告

サブプログラムのコンパイルで曖昧な結果が生成されたり、非効率な構造体が使用された場合、Oracle では警告を発行できます。これらの警告は、PLSQL_WARNINGS初期化パラメータおよび DBMS_WARNINGパッケージを介して選択的に有効または無効にできます。

文字列リテラルの引用符付けメカニズム文字列リテラルの引用符付けメカニズム文字列リテラルの引用符付けメカニズム文字列リテラルの引用符付けメカニズム

文字列リテラル内の一重引用符を二重にするかわりに、リテラル用に独自のデリミタ文字を指定して、文字列内に一重引用符を使用することができます。

CLOB とととと NCLOB 間での暗黙的変換間での暗黙的変換間での暗黙的変換間での暗黙的変換

CLOB から NCLOB、または NCLOB から CLOB に暗黙的変換を実行できます。この操作はコストがかかる可能性があるため、TO_CLOB および TO_NCLOB ファンクションを使用して保全性を継続することが有効である場合があります。

正規表現正規表現正規表現正規表現

UNIX 形式の正規表現に精通しているユーザーは、問合せおよび文字列操作の実行に正規表現を使用できます。SQL 問合せに REGEXP_LIKE演算子を使用し、通常 INSTR、REPLACEおよび SUBSTRを使用する場所に REGEXP_INSTR、REGEXP_REPLACEおよびREGEXP_SUBSTRファンクションを使用します。

参照参照参照参照 :

� 5-17 ページの「コレクションの代入」

� 5-20 ページの「コレクションの比較」

参照参照参照参照 :

� 10-23 ページの「PL/SQL のコンパイル時の警告の概要」

参照参照参照参照 :

� 2-8 ページの「文字列リテラル」

参照参照参照参照 :

� 2-38 ページの「PL/SQL の組込みファンクションのまとめ」

� G-2 ページの「PL/SQL での正規表現の使用」

xxvi

Page 29: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

フラッシュバック問合せのファンクションフラッシュバック問合せのファンクションフラッシュバック問合せのファンクションフラッシュバック問合せのファンクション

SCN_TO_TIMESTAMPおよび TIMESTAMP_TO_SCNファンクションを使用すると、ある時点でのデータベース状態を表すシステム変更番号と日時の間の変換を実行できます。

Oracle9i のののの PL/SQL の新機能の新機能の新機能の新機能

リリースリリースリリースリリース 2((((9.2))))� PL/SQL レコード全体の挿入、更新および選択レコード全体の挿入、更新および選択レコード全体の挿入、更新および選択レコード全体の挿入、更新および選択

レコードの各属性を個別に指定するのではなく、1 つの PL/SQL レコード変数を指定してレコードを SQL 表に挿入したり、更新することができます。また、各 SQL 列に対して個別の PL/SQL 表を使用せずに、行全体を PL/SQL のレコード表に選択することもできます。

� 結合配列結合配列結合配列結合配列

VARCHAR2値で索引付けされたコレクションを作成して、Perl や他の言語のハッシュ表に類似した機能を提供できます。

� ユーザー定義のコンストラクタユーザー定義のコンストラクタユーザー定義のコンストラクタユーザー定義のコンストラクタ

独自のファンクションで、オブジェクト型のシステム・デフォルト・コンストラクタをオーバーライドできます。

参照参照参照参照 :

� 13-160 ページの「SCN_TO_TIMESTAMP ファンクション」

� 13-181 ページの「TIMESTAMP_TO_SCN ファンクション」

参照参照参照参照 :

� 5-46 ページの「PL/SQL レコードのデータベースへの挿入」

� 5-47 ページの「PL/SQL レコード値を使用したデータベースの更新」

� 5-49 ページの「レコードのコレクションへのデータの問合せ」

参照参照参照参照 :

� 5-4 ページの「結合配列(索引付き表)」

参照参照参照参照 :

� 12-18 ページの「オブジェクト・コンストラクタの定義」

xxvii

Page 30: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� UTL_FILE パッケージの拡張パッケージの拡張パッケージの拡張パッケージの拡張

UTL_FILEには、PL/SQL で一般的なファイル管理操作を実行する様々な新しいファンクションが含まれています。

� オブジェクト型用のオブジェクト型用のオブジェクト型用のオブジェクト型用の TREAT ファンクションファンクションファンクションファンクション

オブジェクト・メソッドをコールする時に使用する型継承のレベルを動的に選択できます。つまり、親の型の様々なレベルから、継承するオブジェクト型を参照して、特定の親の型からメソッドをコールできます。このファンクションは、同じ名前の SQL ファンクションと似ています。

� オンライン・マニュアルでのリンクオンライン・マニュアルでのリンクオンライン・マニュアルでのリンクオンライン・マニュアルでのリンク

このマニュアルから他のマニュアルへのほとんどの相互参照が、より詳細になっています。相互参照は、別のマニュアルの目次ではなく、特定の位置にリンクします。この変更は現在進行中のため、すべてのリンクがこの版で改良されているとはかぎりません。このマニュアルのオンライン版は、http://otn.oracle.co.jp/document/で入手できます。オンライン版のマニュアルでは、完全な検索機能を使用できます。

リリースリリースリリースリリース 1((((9.0.1))))� SQL パーサーとパーサーとパーサーとパーサーと PL/SQL パーサーの統合パーサーの統合パーサーの統合パーサーの統合

PL/SQL では、INSERT、UPDATE、DELETEなどの SQL 文の構文が全面的にサポートされています。従来は PL/SQL プログラムで有効な SQL 構文に対してエラーが戻されていた場合がありますが、このリリースからは動作します。

参照参照参照参照 :

� 『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』

参照参照参照参照 :

� 『Oracle Database SQL リファレンス』

参照参照参照参照 : エラー・チェックの一貫性向上により、実行時にエラーが発生するかわりにコンパイル時に無効なコードが検出されたり、その逆になる場合があります。移行手続きの一部としてソース・コードの変更を必要とする場合があります。移行手順の詳細は、『Oracle Database アップグレード・ガイド』を参照してください。

xxviii

Page 31: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� CASE 文および式文および式文および式文および式

CASE 文および式は、IF/THEN の選択肢を複数の代替で表す簡単な方法です。

� 継承および動的メソッド・ディスパッチ継承および動的メソッド・ディスパッチ継承および動的メソッド・ディスパッチ継承および動的メソッド・ディスパッチ

型をスーパータイプ / サブタイプの階層内で宣言できます。サブタイプはスーパータイプから属性とメソッドを継承します。また、サブタイプで新規の属性とメソッドを追加し、既存のメソッドをオーバーライドできます。オブジェクト・メソッドのコールによって、オブジェクトの型に基づいて適切なバージョンのメソッドが実行されます。

� 型の発展型の発展型の発展型の発展

オブジェクト型の属性とメソッドを追加または削除でき、その際に型および対応するデータを再作成する必要はありません。この機能によって、型の階層を事前に全面的に計画するのではなく、アプリケーションの変化に合わせて調整できます。

� 新しい日付新しい日付新しい日付新しい日付 / 時刻型時刻型時刻型時刻型

新しいデータ型 TIMESTAMPでは、秒の小数部を含む時刻値が記録されます。新しいデータ型である TIMESTAMP WITH TIME ZONEおよび TIMESTAMP WITH LOCAL TIME ZONEを使用すると、タイム・ゾーンの違いを考慮して日付値と時刻値を調整できます。クロックが正方向または逆方向にシフトするときの時差を考慮して、タイム・ゾーンに夏時間が適用されるかどうかを指定できます。新しいデータ型であるINTERVAL DAY TO SECONDおよび INTERVAL YEAR TO MONTHは、2 つの日付値および時刻値の時差を表し、日付演算を簡素化します。

参照参照参照参照 :

� 2-32 ページの「CASE 式」

� 4-4 ページの「CASE 文の使用」

� 13-18 ページの「CASE 文」

参照参照参照参照 :

� 12-13 ページの「PL/SQL の型の継承の概要」

� 8-18 ページの「オーバーロードと継承の相互作用」

参照参照参照参照 : 12-12 ページの「既存のオブジェクト型の属性およびメソッドの変更(型の発展)」

xxix

Page 32: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� PL/SQL コードのネイティブ・コンパイルコードのネイティブ・コンパイルコードのネイティブ・コンパイルコードのネイティブ・コンパイル

オラクル社が提供するストアド・プロシージャやユーザーが記述するストアド・プロシージャを、代表的な C の開発ツールを使用してシステム固有の実行可能ファイルにコンパイルして、パフォーマンスを改善します。この設定は保存されるため、プロシージャは後で無効になった場合も同じ方法でコンパイルされます。

� 改善されたグローバリゼーションおよび各国語サポート改善されたグローバリゼーションおよび各国語サポート改善されたグローバリゼーションおよび各国語サポート改善されたグローバリゼーションおよび各国語サポート

固定幅または可変幅のキャラクタ・セットを使用し、データを Unicode 形式で格納できます。文字列の処理とストレージの宣言は、バイト長または文字長で指定できます。文字長で指定すると、バイト数が計算されます。データベース全体を、文字列に同じ長さのセマンティクスを使用するように設定したり、個々のプロシージャの設定を指定することができます。プロシージャが無効になった場合は、この設定は記憶されます。

� テーブル・ファンクションとカーソル式テーブル・ファンクションとカーソル式テーブル・ファンクションとカーソル式テーブル・ファンクションとカーソル式

戻される行のセットを表のように問合せできます。ある関数から別の関数に結果セットを渡すことができるため、表に中間結果を保持せずに一連の変換を設定できます。結果セットの行を一度に少しずつ戻し、1 つの関数で多数の結果セットが生成された場合のメモリー・オーバーヘッドを削減します。

参照参照参照参照 :

� 3-15 ページの「PL/SQL の日付型、時刻型および時間隔型」

� 3-20 ページの「日時および時間隔の演算」

� 2-9 ページの「日時リテラル」

参照参照参照参照 : 11-28 ページの「システム固有の実行のための PL/SQL コードのコンパイル」

参照参照参照参照 :

� 3-6 ページの「PL/SQL の文字型と文字列型」

� 3-11 ページの「PL/SQL の各国語キャラクタ・タイプ」

参照参照参照参照 :

� 11-36 ページの「テーブル・ファンクションでの変換パイプラインの設定」

� 6-35 ページの「カーソル式の使用」

xxx

Page 33: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� マルチレベル・コレクションマルチレベル・コレクションマルチレベル・コレクションマルチレベル・コレクション

PL/SQL 表の VARRAY、VARRAYの VARRAY、PL/SQL 表の PL/SQL 表などを作成するために、コレクション型をネストできます。マルチディメンション配列など、複雑なデータ構造のモデルを通常の方法で作成できます。

� LOB データ型の適切な統合データ型の適切な統合データ型の適切な統合データ型の適切な統合

LOB 型を類似する他の型と同様に操作できます。CLOBおよび NCLOB型に文字関数を使用できます。BLOB型を RAWとして扱うことができます。LOB と他の型との変換は、特に LONG型から LOB 型に変換する場合には、はるかに単純化されます。

� バルク操作の強化バルク操作の強化バルク操作の強化バルク操作の強化

システム固有の動的 SQL(EXECUTE IMMEDIATE文)を使用して、バルク・フェッチなどのバルク SQL 操作を実行できます。一部の行にエラーがあっても継続するバルク挿入操作やバルク更新操作を実行し、操作の完了後に問題を検査できます。

� MERGE 文文文文

この特化された文によって、挿入と更新が組み合されて 1 つの操作になります。これは、特定パターンの挿入と更新を実行するデータ・ウェアハウス・アプリケーションを意図しています。

参照参照参照参照 : 5-27 ページの「マルチレベル・コレクションの使用」

参照参照参照参照 : 3-13 ページの「PL/SQL LOB 型」

参照参照参照参照 :

� 11-9 ページの「DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)」

� 7-8 ページの「バルク動的 SQL の使用」

� 13-65 ページの「EXECUTE IMMEDIATE 文」

参照参照参照参照 :

� 概要と例は、13-113 ページの「MERGE 文」を参照してください。

� 詳細は、『Oracle Database SQL リファレンス』を参照してください。

xxxi

Page 34: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

xxxii

Page 35: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の

1

PL/SQL の概要の概要の概要の概要

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

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

� PL/SQL のメリット(1-2 ページ)

� PL/SQL の主な特長(1-5 ページ)

� PL/SQL アーキテクチャ(1-16 ページ)

参照参照参照参照 : PL/SQL に関する追加情報とサンプル・コードについては、次のURL で OTN-J(Oracle Technology Network Japan)にアクセスしてください。

http://otn.oracle.co.jp/tech/pl_sql/

概要 1-1

Page 36: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のメリット

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

� SQL のサポート

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

� 高いパフォーマンス

� 高い生産性

� 完全な移植性

� Oracle との緊密な統合

� 優れたセキュリティ

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

PL/SQL における SQL 問合せの実行および結果セットの処理は、一般的なスクリプト言語でテキスト・ファイルを開いて各行を処理する場合と同様に簡単です。

データベース・オブジェクトのメタデータへのアクセスおよびデータベースのエラー条件の処理に PL/SQL を使用して、データベース管理用のユーティリティ・プログラムを作成できます。このプログラムは信頼性が高く、各操作が正常に終了したかどうかの出力を読みやすい形式で生成します。

PL/SQL は、トリガーやオブジェクト型など、データベースの多くの機能で使用されます。トリガー本体およびオブジェクト型のメソッドを PL/SQL で作成できます。

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

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

1-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 37: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のメリット

PL/SQL はプログラミング技術の動的 SQL もサポートしており、これによってアプリケーションをより柔軟で多目的に使用できます。プログラムでは、表名や WHERE句などの詳細情報が事前にわからない場合でも、SQL データ定義文、データ制御文、セッション制御文を実行時に作成して処理できます。

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

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

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

PL/SQL の概要 1-3

Page 38: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のメリット

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

高い生産性高い生産性高い生産性高い生産性PL/SQL は、Oracle Forms や Oracle Reports などのツールを拡張します。これらのツールでPL/SQL を使用すると、使い慣れた言語の構造体を使用してアプリケーションを構築できます。たとえば、複数のトリガー・ステップ、マクロまたはユーザー・イグジットを使用するかわりに、Oracle Forms トリガーの中で PL/SQL ブロック全体を使用できます。

また、PL/SQL はどの環境でも同じです。ある 1 つの Oracle ツールで習得した PL/SQL の知識は他のツールにも利用できます。

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

1-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 39: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

優れたセキュリティ優れたセキュリティ優れたセキュリティ優れたセキュリティPL/SQL ストアド・プロシージャは、クライアントからサーバーへアプリケーション・コードを移動します。サーバーでは、コードの改ざんの防止、コード内の細部の隠ぺいおよびアクセスの制限が可能になります。たとえば、表を更新するプロシージャへのアクセス権をユーザーに付与して、表自体または UPDATE文のテキストへのアクセス権は付与しないようにできます。

PL/SQL で作成されたトリガーは、データへの変更を制御および記録して、すべての変更がビジネス・ルールに従っていることを確認します。

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

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

さらに、オブジェクト型を使用することで、現実のデータをモデル化できます。複雑な実世界のエンティティと関連は、オブジェクト型に直接対応付けることができます。この直接マッピングは、プログラムがシミュレートしている世界をより適切に反映するために役立ちます。

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

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

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

PL/SQL の概要 1-5

Page 40: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

ブロック構造ブロック構造ブロック構造ブロック構造PL/SQL プログラムを構成する基本単位(プロシージャ、ファンクションおよび無名ブロック)は、内部で相互にネストできる論理ブロックです。

ブロックは、関連する宣言および文をグループ化します。宣言は、それを使用する場所に近い場所に置くことができます。大規模なサブプログラムの内部でも可能です。宣言はブロックの中で局所的に有効で、そのブロックが終了すると消滅します。これによって、変数およびプロシージャの名前空間が一杯になることを回避できます。

図 1-2 に示すとおり、PL/SQL ブロックは宣言部、実行部およびエラー条件を処理する例外処理部の 3 つの部分で構成されます。このうち存在する必要があるのは実行部のみです。

初にあるのは宣言部で、ここでは型や変数などの項目を定義できます。宣言した項目は、実行部で操作できます。実行の間に起動された例外は、例外処理部で処理されます。

図図図図 1-2 ブロック構造ブロック構造ブロック構造ブロック構造

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

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

[DECLARE -- declarations]BEGIN -- statements[EXCEPTION -- handlers]END;

1-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 41: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

変数の宣言変数の宣言変数の宣言変数の宣言変数は、CHAR、DATE、NUMBERなどの任意の SQL データ型や、BOOLEAN、PLS_INTEGERなどの PL/SQL 固有のデータ型を持つことができます。たとえば、4 桁の数字が入るpart_noという名前の変数と、ブール値 TRUEまたは FALSEが入る in_stockという名前の変数を宣言します。この場合、変数の宣言は次のようにします。

part_no NUMBER(4);in_stock BOOLEAN;

コンポジット・データ型 TABLE、VARRAY、RECORDを使用して、ネストした表、可変サイズの配列(VARRAY)およびレコードも宣言できます。

変数への値の代入変数への値の代入変数への値の代入変数への値の代入変数に値を代入する方法は 3 つあります。1 つ目は、コロンに等号を付けた代入演算子

(:=)を使用する方法です。変数は演算子の左に、ファンクション・コールを含む式は演算子の右に置きます。次に例を示します。

tax := price * tax_rate;valid_id := FALSE;bonus := current_salary * 0.10;wages := gross_pay(emp_id, st_hrs, ot_hrs) - deductions;

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

SELECT salary * 0.10 INTO bonus FROM employees WHERE employee_id = emp_id;

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

DECLARE my_sal REAL(7,2); PROCEDURE adjust_salary (emp_id INT, salary IN OUT REAL) IS ...BEGIN SELECT AVG(sal) INTO my_sal FROM emp; adjust_salary(7788, my_sal); -- assigns a new value to my_sal

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

credit_limit CONSTANT NUMBER := 5000.00;

PL/SQL の概要 1-7

Page 42: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

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

FOR someone IN (SELECT * FROM employees)LOOP DBMS_OUTPUT.PUT_LINE('First name = ' || someone.first_name); DBMS_OUTPUT.PUT_LINE('Last name = ' || someone.last_name);END LOOP;

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

PL/SQL 変数の宣言変数の宣言変数の宣言変数の宣言各 PL/SQL 変数の宣言の一部として、変数のデータ型を宣言します。通常、変数のデータ型には、NUMBER、VARCHAR2(length)などの、PL/SQL と SQL で共有されるデータ型を使用します。特別な修飾子 %TYPEおよび %ROWTYPEを使用して表の列または表の行を保持する変数を宣言すると、データベースと相互作用するコードのメンテナンスがより簡単になります。

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

my_title books.title%TYPE;

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

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

1-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 43: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

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

DECLARE dept_rec dept%ROWTYPE; -- declare record variable

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

my_deptno := dept_rec.deptno;

従業員の姓、給与、入社日および役職を取り出すカーソルを宣言する場合、次のように%ROWTYPEを使用して、同じ情報を格納するレコードを宣言できます。

DECLARE CURSOR c1 IS SELECT ename, sal, hiredate, job FROM emp; emp_rec c1%ROWTYPE; -- declare record variable that represents -- a row fetched from the emp table

次の文を実行すると想定します。

FETCH c1 INTO emp_rec;

emp表の ename列の値は emp_recの enameフィールドに、sal列の値は salフィールドに、というように代入されます。

制御構造制御構造制御構造制御構造制御構造は、SQL に対して加えられた PL/SQL の も重要な機能拡張です。PL/SQL を使用すると、Oracle データを操作できるのみでなく、IF-THEN-ELSE、CASE、FOR-LOOP、WHILE-LOOP、EXIT-WHEN、GOTOなどの条件制御文、反復制御文および順次制御文を使用してデータを処理できます。

条件制御条件制御条件制御条件制御状況に応じてアクションを選択する必要のある場面はよくあります。IF-THEN-ELSE文を使用すると、一連の文を条件に合わせて実行できます。IF句で条件を検査します。THEN句で条件が TRUE の場合のアクションを定義し、ELSE句では条件が FALSE または NULL の場合のアクションを定義します。

次のような、銀行のトランザクションを処理するプログラムを考えます。口座 3 から $500を引き出す前に、プログラムは口座に引き出しができるだけの預金があるかどうかを確認します。預金があれば、プログラムは口座に出金を記入します。預金がない場合は、監査表にレコードを挿入します。

PL/SQL の概要 1-9

Page 44: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

-- available online in file 'examp2'DECLARE acct_balance NUMBER(11,2); acct CONSTANT NUMBER(4) := 3; debit_amt CONSTANT NUMBER(5,2) := 500.00;BEGIN SELECT bal INTO acct_balance FROM accounts WHERE account_id = acct FOR UPDATE OF bal; IF acct_balance >= debit_amt THEN UPDATE accounts SET bal = bal - debit_amt WHERE account_id = acct; ELSE INSERT INTO temp VALUES (acct, acct_balance, 'Insufficient funds'); -- insert account, current balance, and message END IF; COMMIT;END;

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

-- This CASE statement performs different actions based-- on a set of conditional tests.CASE WHEN shape = 'square' THEN area := side * side; WHEN shape = 'circle' THEN BEGIN area := pi * (radius * radius); DBMS_OUTPUT.PUT_LINE('Value is not exact because pi is irrational.'); END; WHEN shape = 'rectangle' THEN area := length * width; ELSE BEGIN DBMS_OUTPUT.PUT_LINE('No formula to calculate area of a' || shape); RAISE PROGRAM_ERROR; END;END CASE;

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

1-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 45: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

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

LOOP -- sequence of statementsEND LOOP;

FOR-LOOP文では、整数の範囲を指定し、範囲中のそれぞれの整数に対して一連の文を 1 回実行できます。たとえば、次のループでは、500 個の数とその平方根がデータベース表に挿入されます。

FOR num IN 1..500 LOOP INSERT INTO roots VALUES (num, SQRT(num));END LOOP;

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

次の例では、従業員 7499 よりも指揮系統内で上位にあり、給与が $2500 よりも高い 初の従業員を探しています。

-- available online in file 'examp3'DECLARE salary emp.sal%TYPE := 0; mgr_num emp.mgr%TYPE; last_name emp.ename%TYPE; starting_empno emp.empno%TYPE := 7499;BEGIN SELECT mgr INTO mgr_num FROM emp WHERE empno = starting_empno; WHILE salary <= 2500 LOOP SELECT sal, mgr, ename INTO salary, mgr_num, last_name FROM emp WHERE empno = mgr_num; END LOOP; INSERT INTO temp VALUES (NULL, salary, last_name); COMMIT;EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO temp VALUES (NULL, NULL, 'Not found'); COMMIT;END;

PL/SQL の概要 1-11

Page 46: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

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

LOOP ... total := total + salary; EXIT WHEN total > 25000; -- exit loop if condition is trueEND LOOP;-- control resumes here

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

IF rating > 90 THEN GOTO calc_raise; -- branch to labelEND IF;...<<calc_raise>>IF job_title = 'SALESMAN' THEN -- control resumes here amount := commission * 0.25;ELSE amount := salary * 0.10;END IF;

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

1-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 47: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

サブプログラムサブプログラムサブプログラムサブプログラムPL/SQL にはプロシージャとファンクションの 2 種類のサブプログラムがあり、そのどちらもパラメータを取り、起動(コール)できます。次の例に示すように、サブプログラムはプログラムのミニチュアのようなもので、ヘッダーから始まって宣言部(オプション)、実行部、例外処理部(オプション)が続きます。

PROCEDURE award_bonus (emp_id NUMBER) IS bonus REAL; comm_missing EXCEPTION;BEGIN -- executable part starts here SELECT comm * 0.15 INTO bonus FROM emp WHERE empno = emp_id; IF bonus IS NULL THEN RAISE comm_missing; ELSE UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id; END IF;EXCEPTION -- exception-handling part starts here WHEN comm_missing THEN ...END award_bonus;

このプロシージャは、コール時に従業員番号を受け付けます。この番号を使用してデータベース表から従業員のコミッションを選択し、同時に 15% のボーナスを計算します。次に、ボーナスの金額を検査します。ボーナスが NULL の場合は例外が呼び出され、NULL でない場合は従業員の給与台帳レコードが更新されます。

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

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

次の例のパッケージには、2 つの人事プロシージャが含まれています。

CREATE PACKAGE emp_actions AS -- package specification PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...); PROCEDURE fire_employee (emp_id NUMBER);END emp_actions;

CREATE PACKAGE BODY emp_actions AS -- package body PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...) IS

PL/SQL の概要 1-13

Page 48: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

BEGIN INSERT INTO emp VALUES (empno, ename, ...); END hire_employee; PROCEDURE fire_employee (emp_id NUMBER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee;END emp_actions;

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

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

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

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

要素を参照するには、カッコを使用した添字表記法を使用します。たとえば、次のコールはファンクション new_hiresが戻すネストした表の 5 番目の要素(Staff型)を参照します。

DECLARE TYPE Staff IS TABLE OF Employee; staffer Employee; FUNCTION new_hires (hiredate DATE) RETURN Staff IS BEGIN ... END;BEGIN staffer := new_hires('10-NOV-98')(5);END;

1-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 49: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の主な特長

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

レコードレコードレコードレコードレコードのデータ構造はコンポジット型で、フィールドには様々なデータ型を含めることができます。レコードを使用すると、関連する項目を保持し、単一のパラメータでサブプログラムにこれらの項目を渡すことができます。

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

次の例を考えます。

DECLARE TYPE TimeRec IS RECORD (hours SMALLINT, minutes SMALLINT); TYPE MeetingTyp IS RECORD ( date_held DATE, duration TimeRec, -- nested record location VARCHAR2(20), purpose VARCHAR2(50));

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

オブジェクト型によって、大規模なシステムが複数の論理エンティティに細分化されるため、複雑さが軽減されます。これによって、モジュール構造を持ち、保持および再利用が可能なソフトウェア・コンポーネントを作成できます。

オブジェクト型の定義およびメソッドのコードは、データベースに格納されます。これらのオブジェクト型のインスタンスは、表に格納するか、または PL/SQL コード内で変数として使用できます。

CREATE TYPE Bank_Account AS OBJECT ( acct_number INTEGER(5), balance REAL, status VARCHAR2(10), MEMBER PROCEDURE open (amount IN REAL), MEMBER PROCEDURE verify_acct (num IN INTEGER), MEMBER PROCEDURE close (num IN INTEGER, amount OUT REAL), MEMBER PROCEDURE deposit (num IN INTEGER, amount IN REAL), MEMBER PROCEDURE withdraw (num IN INTEGER, amount IN REAL), MEMBER FUNCTION curr_bal (num IN INTEGER) RETURN REAL );

PL/SQL の概要 1-15

Page 50: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アーキテクチャ

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

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

エラーであると定義した条件に対して、または通常は ORA- エラー・メッセージが表示されるデータベース・エラーに対応するように、独自の例外を定義できます。ユーザー定義のエラー条件を検出した場合は、RAISE文を実行します。次の例では、営業担当者に支給されるボーナスを計算しています。ボーナスは給与とコミッションに基づいて計算されます。コミッションが NULL の場合は例外 comm_missingが呼び出されます。

DECLARE comm_missing EXCEPTION; -- declare exceptionBEGIN IF commission IS NULL THEN RAISE comm_missing; -- raise exception END IF; bonus := (salary * 0.10) + (commission * 0.15);EXCEPTION WHEN comm_missing THEN ... -- process the exception

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

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

1-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 51: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アーキテクチャ

図図図図 1-3 PL/SQL エンジンエンジンエンジンエンジン

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

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

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

パッケージ内で定義されたストアド・サブプログラムは、パッケージ・サブプログラムと呼ばれます。独立して定義されたものは、スタンドアロン・サブプログラムと呼ばれます。

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

PL/SQL の概要 1-17

Page 52: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アーキテクチャ

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

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

たとえば、スタンドアロン・プロシージャ create_deptは、次のようにして SQL*Plus からコールします。

SQL> CALL create_dept('FINANCE', 'NEW YORK');

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

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

CREATE TRIGGER audit_sal AFTER UPDATE OF sal ON emp FOR EACH ROWBEGIN INSERT INTO emp_audit VALUES ...END;

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

1-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 53: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アーキテクチャ

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

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

PL/SQL の概要 1-19

Page 54: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アーキテクチャ

1-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 55: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 言語の

2

PL/SQL 言語の基礎言語の基礎言語の基礎言語の基礎

前の章では、PL/SQL の概要を示しました。この章では、PL/SQL を詳細に説明します。他のプログラミング言語と同様に、PL/SQL にはキャラクタ・セット、予約語、デリミタ、データ型および一定の構文規則があります。

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

� キャラクタ・セット(2-2 ページ)

� 字句単位(2-2 ページ)

� 宣言(2-11 ページ)

� PL/SQL のネーミング規則(2-16 ページ)

� PL/SQL の識別子の有効範囲と可視性(2-19 ページ)

� 変数への値の代入(2-22 ページ)

� PL/SQL の式および比較(2-23 ページ)

� PL/SQL の組込みファンクションのまとめ(2-38 ページ)

基礎 2-1

Page 56: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

キャラクタ・セット

キャラクタ・セットキャラクタ・セットキャラクタ・セットキャラクタ・セットPL/SQL プログラムは、特定のキャラクタ・セットを使用したテキストとして作成されます。

大文字と小文字の英字、A~ Zおよび a~ z数字、0~ 9記号、( ) + - * / < > = ! ~ ^ ; : . ' @ % , " # $ & _ | { } ? [ ]タブ、空白および改行

PL/SQL キーワードは大 / 小文字が区別されないため、文字列リテラルと文字リテラルの中を除き、小文字の英字は対応する大文字の英字と等価です。

字句単位字句単位字句単位字句単位PL/SQL テキストの行には字句単位と呼ばれる文字のグループがあります。

デリミタ(単純記号とコンパウンド記号)識別子(予約語を含む)リテラルコメント

わかりやすくするために、字句単位は空白で区切ることができます。実際には、隣接する識別子は、空白またはデリミタで区切る必要があります。次の行は予約語の ENDと IFが結合されているため、不正です。

IF x > y THEN high := x; ENDIF; -- not allowed, must be END IF

文字列リテラルとコメントの場合を除き、字句単位の中に空白を埋め込むことはできません。たとえば、次の行は代入を表すコンパウンド記号(:=)が分かれているため、不正です。

count : = count + 1; -- not allowed, must be :=

構造を示すために、改行で行を分けたり、空白またはタブで行にインデントを付けることができます。右の IF文のように文の形式を整えると、より見やすくなります。

IF x>y THEN max:=x;ELSE max:=y;END IF; | IF x > y THEN | max := x; | ELSE | max := y; | END IF;

2-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 57: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

デリミタデリミタデリミタデリミタデリミタは、PL/SQL にとって特別な意味を持つ単純記号またはコンパウンド記号です。たとえば、デリミタを使用して加算や減算などの算術演算を表現できます。

記号記号記号記号 意味意味意味意味

+ 加算演算子

% 属性のインジケータ

' 文字列のデリミタ

. 構成要素の選択子

/ 除算演算子

( 式またはリストのデリミタ

) 式またはリストのデリミタ

: ホスト変数のインジケータ

, 項目のセパレータ

* 乗算演算子

" 二重引用符で囲んだ識別子のデリミタ

= 関係演算子

< 関係演算子

> 関係演算子

@ リモート・アクセスのインジケータ

; 文の終了記号

- 減算 / 否定演算子

記号記号記号記号 意味意味意味意味

:= 代入演算子

=> 結合演算子

|| 連結演算子

** 指数演算子

<< ラベルのデリミタ(開始)

>> ラベルのデリミタ(終了)

PL/SQL 言語の基礎 2-3

Page 58: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

識別子識別子識別子識別子識別子を使用して、定数、変数、例外、カーソル、カーソル変数、サブプログラム、パッケージなどの PL/SQL プログラムに名前を付けることができます。次に識別子の例をいくつか示します。

Xt2phone#credit_limitLastNameoracle$number

識別子は英字 1 文字でもかまいませんが、後に英字、数字、ドル記号、アンダースコアおよびシャープ記号を続けることもできます。次の例のように、ハイフン、スラッシュ、空白などの文字は使用できません。

mine&yours -- not allowed because of ampersanddebit-amount -- not allowed because of hyphenon/off -- not allowed because of slashuser id -- not allowed because of space

ドル記号、アンダースコアおよびシャープ記号を隣接して使用したり、先頭以外の位置で使用することができます。

money$$$treeSN## try_again_

/* 複数行コメントのデリミタ(開始)

*/ 複数行コメントのデリミタ(終了)

.. 範囲演算子

<> 関係演算子

!= 関係演算子

~= 関係演算子

^= 関係演算子

<= 関係演算子

>= 関係演算子

-- 単一行コメントのインジケータ

記号記号記号記号 意味意味意味意味

2-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 59: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

識別子では大文字と小文字が使用でき、両者の混用もできます。PL/SQL では、文字列リテラルと文字リテラルの中を除いて、大 / 小文字は区別されません。したがって、2 つの識別子の違いが英字の大 / 小文字の違いのみであれば、PL/SQL は同じ識別子とみなします。

lastnameLastName -- same as lastnameLASTNAME -- same as lastname and LastName

識別子のサイズは 30 文字以内にする必要があります。ドル記号、アンダースコアおよびシャープ記号を含むすべての文字が意味を持ちます。たとえば、PL/SQL は、次の 2 つの識別子を別のものとして扱います。

lastnamelast_name

識別子は、内容がわかりやすいものにしてください。cpmのようなあいまいな名前は避けます。かわりに、cost_per_thousandのように意味のわかりやすい名前を使用してください。

予約語予約語予約語予約語識別子には、PL/SQL に対して構文上の特別な意味を持つ予約語があります。たとえば、BEGINと ENDは予約語です。予約語を再定義しようとするとコンパイル・エラーが発生します。ただし、識別子の中に予約語を埋め込むことはできます。

DECLARE -- end BOOLEAN; -- not allowed; causes compilation error end_of_game BOOLEAN; -- allowedBEGIN NULL;END;/

一般に、予約語は区別しやすくするために大文字で書かれています。予約語のリストは、付録 F を参照してください。

事前定義の識別子事前定義の識別子事前定義の識別子事前定義の識別子例外 INVALID_NUMBERなど、パッケージ STANDARDでグローバルに宣言されている識別子は、再宣言できます。ただし、事前定義の識別子を再宣言すると、ローカルな宣言がグローバルな宣言をオーバーライドするためエラーが発生しやすくなります。

PL/SQL 言語の基礎 2-5

Page 60: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

二重引用符で囲んだ識別子二重引用符で囲んだ識別子二重引用符で囲んだ識別子二重引用符で囲んだ識別子柔軟性を高めるために、PL/SQL では識別子を二重引用符で囲むことができます。通常は、このようにする必要はありませんが、ときには便利な場合もあります。二重引用符で囲んだ識別子には、空白など、二重引用符を除くすべての印字可能文字を任意に並べて入れることができます。したがって、次の識別子は有効です。

"X+Y""last name""on/off switch""employee(s)""*** header info ***"

二重引用符で囲んだ識別子の 大サイズは、二重引用符を数えずに 30 字です。PL/SQL の予約語を二重引用符で囲んだ識別子として使用することもできますが、それは好ましくないプログラミング習慣です。

リテラルリテラルリテラルリテラルリテラルは、識別子によって表現する必要がない明示的な数値、文字、文字列またはブール値です。例として、数値リテラル 147やブール・リテラル FALSEがあります。

数値リテラル数値リテラル数値リテラル数値リテラル算術式では、整数と実数の 2 種類の数値リテラルを使用できます。整数リテラルは、小数点を持たず、必要に応じて符号を付けた整数です。次に例を示します。

030 6 -14 0 +32767

実数リテラルとは、小数点を持ち、必要に応じて符号を付けた整数または小数です。次に例を示します。

6.6667 0.0 -12.0 3.14159 +8300.00 .5 25.

PL/SQL では、12.0や 25.などの数字は、整数値がある場合でも実数とみなします。

数値リテラルはドル記号やカンマを含むことはできませんが、科学表記法で書くことができます。数字の後に E(または e)を付けて、必要な場合は符号付き整数を続けます。次に例を示します。

2E5 1.0E-7 3.14159e0 -1E38 -9.5e-3

Eは、「10 の累乗」を意味します。次の例で示すように、Eの前の数に、Eの後の数の 10 の累乗を掛けます(二重アスタリスク(**)は指数演算子です)。

5E3 = 5 * 10**3 = 5 * 1000 = 5000

2-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 61: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

Eの後の数値は、小数点が移動する桁数にも対応しています。上の例では、暗黙的な小数点が 3 桁右に移動しました。次の例では、3 桁左に移動します。

5E-3 = 5 * 10**-3 = 5 * 0.001 = 0.005

次の例に示すように、数値リテラルの値が 1E-130~ 10E125の範囲外の場合、コンパイル・エラーが発生します。

DECLARE n NUMBER;BEGIN n := 10E127; -- causes a 'numeric overflow or underflow' errorEND;/

実数リテラルには、後ろに fまたは d文字を付けて、それぞれ BINARY_FLOATまたはBINARY_DOUBLE型を指定できます。

DECLARE x BINARY_FLOAT := sqrt(2.0f); -- Single-precision floating-point number y BINARY_DOUBLE := sqrt(2.0d); -- Double-precision floating-point numberBEGIN NULL;END;/

文字リテラル文字リテラル文字リテラル文字リテラル文字リテラルは引用符(アポストロフィ)で囲まれた 1 文字のことです。文字リテラルには、PL/SQL キャラクタ・セットのすべての印刷可能文字(英字、数字、空白および特殊記号)を使用できます。次に例を示します。

'Z' '%' '7' ' ' 'z' '('

文字リテラルの中で、PL/SQL は大 / 小文字を区別します。このため、PL/SQL はリテラル'Z'と 'z'を違うものとして扱います。また文字リテラル '0'~ '9'は、整数リテラルと同じではありませんが、暗黙のうちに整数に変換されるため、算術式の中で使用できます。

PL/SQL 言語の基礎 2-7

Page 62: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

文字列リテラル文字列リテラル文字列リテラル文字列リテラル文字値は、識別子によって表現することも、引用符(')で囲まれた 0(ゼロ)文字以上の並びである文字列リテラルとして明示的に書くこともできます。次に例を示します。

'Hello, world!''XYZ Corporation''10-NOV-91''He said "Life is like licking honey from a thorn."''$1,000,000'

NULL 文字列('')を除くすべての文字列リテラルは、CHARデータ型に属します。

文字列の中でアポストロフィを表現する場合は、引用符を 2 つ書きます。これは二重引用符を書く場合とは違う意味を持ちます。

'I''m a string, you''re a string.'

複雑なリテラル内で引用符を二重にする場合(特に SQL 文を表すもの)は、注意が必要です。次の表記法を使用して、リテラルに独自のデリミタ文字を定義することもできます。デリミタ文字には、文字列に含まれていない文字を使用します。これによって、リテラル内の引用符をエスケープする必要がなくなります。

-- q'!...!' notation lets us use single quotes inside the literal.string_var := q'!I'm a string, you're a string.!';

-- To use delimiters [, {, <, and (, pair them with ], }, >, and ).-- Here we pass a string literal representing a SQL statement-- to a subprogram, without doubling the quotation marks around-- 'INVALID'.func_call(q'[select index_name from user_indexes where status = 'INVALID']');

-- For NCHAR and NVARCHAR2 literals, use the prefix nq instead of q.where_clause := nq'#where col_value like '%é'#';

文字列リテラルの中で、PL/SQL は大 / 小文字を区別します。たとえば、PL/SQL は次の 2つのリテラルを異なるものとして扱います。

'baker''Baker'

ブール・リテラルブール・リテラルブール・リテラルブール・リテラルブール・リテラルとは、事前定義の値 TRUEと FALSE、および NULL(存在しない値、未知の値または適用不可能な値を表す)のことです。ブール・リテラルは値であり、文字列ではないことに注意してください。たとえば、TRUEは数値 25と同じように 1 つの値です。

2-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 63: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

日時リテラル日時リテラル日時リテラル日時リテラル日時リテラルには、データ型に応じて様々な形式があります。次に例を示します。

DECLARE d1 DATE := DATE '1998-12-25'; t1 TIMESTAMP := TIMESTAMP '1997-10-22 13:01:01'; t2 TIMESTAMP WITH TIME ZONE := TIMESTAMP '1997-01-31 09:26:56.66 +02:00';-- Three years and two months-- (For greater precision, we would use the day-to-second interval) i1 INTERVAL YEAR TO MONTH := INTERVAL '3-2' YEAR TO MONTH;-- Five days, four hours, three minutes, two and 1/100 seconds i2 INTERVAL DAY TO SECOND := INTERVAL '5 04:03:02.01' DAY TO SECOND;

特定の時間隔値が YEAR TO MONTHであるか DAY TO SECONDであるかも指定できます。たとえば、current_timestamp - current_timestampでは、デフォルトでINTERVAL DAY TO SECOND型の値が生成されます。時間隔の型は、次の形式で指定できます。

� (interval_expression) DAY TO SECOND

� (interval_expression) YEAR TO MONTH

日付および時刻型の構文の詳細は、『Oracle Database SQL リファレンス』を参照してください。日付 / 時刻算術の実行例は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

コメントコメントコメントコメントPL/SQL コンパイラはコメントを無視しますが、ユーザーはコメントを無視しないでください。プログラムにコメントを付け加えると、わかりやすくなり理解に役立ちます。一般に、コメントは各コード・セグメントの目的や使用方法を説明するために使用します。PL/SQLでは、単一行コメントと複数行コメントの 2 種類のコメント形式がサポートされています。

単一行コメント単一行コメント単一行コメント単一行コメント単一行コメントは、行の中の任意の位置にある二重ハイフン(--)から始まり、その行の終わりまで続きます。次に例を示します。

DECLARE howmany NUMBER;BEGIN-- begin processing SELECT count(*) INTO howmany FROM user_objects WHERE object_type = 'TABLE'; -- Check number of tables howmany := howmany * 2; -- Compute some other valueEND;/

PL/SQL 言語の基礎 2-9

Page 64: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

字句単位

コメントは、行の末尾であれば文の途中でも使用できることに注意してください。

プログラムのテストやデバッグのときに、コード中の 1 行を無効にする場合があります。行を「コメントにする」方法を次の例に示します。

-- DELETE FROM employees WHERE comm_pct IS NULL;

複数行コメント複数行コメント複数行コメント複数行コメント複数行コメントは、スラッシュ - アスタリスク(/*)で始まってアスタリスク - スラッシュ

(*/)で終わり、複数行にまたがることができます。次に例を示します。

DECLARE some_condition BOOLEAN; pi NUMBER := 3.1415926; radius NUMBER := 15; area NUMBER;BEGIN /* Perform some simple tests and assignments */ IF 2 + 2 = 4 THEN some_condition := TRUE; /* We expect this THEN to always be done */ END IF;/* The following line computes the area of a circle using pi, which is the ratio between the circumference and diameter.*/ area := pi * radius**2;END;/

複数行コメントのデリミタを使用すると、コードの一部分をすべてコメントにできます。

/*LOOP FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; ...END LOOP;*/

コメントの制限コメントの制限コメントの制限コメントの制限コメントはネストできません。

また、Oracle プリコンパイラ・プログラムが処理する PL/SQL ブロックの中では、単一行コメントは使用できません。これは、行の終わりを示す文字が無視され、単一行コメントが行の終わりでなくブロックの終わりまで続いてしまうためです。この場合、かわりに /* */表記法を使用します。

2-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 65: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言

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

変数および定数は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で宣言できます。宣言によって、値の記憶域を割り当て、データ型を指定し、値を参照できるように格納場所の名前を決めます。

次に例を示します。

DECLARE birthday DATE; emp_count SMALLINT := 0;

1 つ目の宣言で、DATE型の変数の名前を決めています。2 つ目の宣言で、SMALLINT型の変数の名前を決め、代入演算子を使用して変数に初期値 0 を代入しています。

代入演算子の後に続く式は複雑なものでもかまいません。また、事前に初期化されている変数を参照することもできます。

DECLARE pi REAL := 3.14159; radius REAL := 1; area REAL := pi * radius**2;BEGIN NULL;END;/

変数はデフォルトで NULLに初期化されます。そのため、変数宣言に「:= NULL」を含めると冗長になります。

定数を宣言するには、型指定子の前にキーワード CONSTANTが必要です。

DECLARE credit_limit CONSTANT REAL := 5000.00; max_days_in_year CONSTANT INTEGER := 366; urban_legend CONSTANT BOOLEAN := FALSE;BEGIN NULL;END;/

この宣言では、REAL型の定数の名前を決め、定数に変更不可能な値 5000 を代入しています。定数は、宣言の中で初期化する必要があります。それ以外の場合は、コンパイル・エラーが発生します。

PL/SQL 言語の基礎 2-11

Page 66: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言

DEFAULT の使用の使用の使用の使用変数の初期化には、代入演算子のかわりにキーワード DEFAULTも使用できます。次に例を示します。

blood_type CHAR := 'O';

この宣言は、次のように書き換えることができます。

blood_type CHAR DEFAULT 'O';

標準的な値を持つ変数には、DEFAULTを使用します。特殊な値を持つ変数(カウンタやアキュムレータ)には、代入演算子を使用します。次に例を示します。

hours_worked INTEGER DEFAULT 40;employee_count INTEGER := 0;

DEFAULTを使用して、サブプログラム・パラメータ、カーソル・パラメータおよびユーザー定義レコードのフィールドを初期化することもできます。

NOT NULL の使用の使用の使用の使用宣言によって、初期値を代入する以外に NOT NULL制約を付けることもできます。

DECLARE acct_id INTEGER(4) NOT NULL := 9999;

NOT NULLと定義されている変数には NULL を代入できません。NULL を代入しようとすると、PL/SQL は事前定義の例外 VALUE_ERRORを呼び出します。

NOT NULL制約の後に初期化句を続ける必要があります。

PL/SQL では、サブタイプ NATURALNと POSITIVENは、あらかじめ NOT NULLとして定義されています。これらの型の変数を宣言する場合は、NOT NULL制約を省略できますが、初期化句を含める必要があります。

%TYPE 属性の使用属性の使用属性の使用属性の使用%TYPE属性は、変数またはデータベース列のデータ型を与えます。次の例では、%TYPE属性は変数のデータ型を与えています。

DECLARE credit NUMBER(7,2); debit credit%TYPE; name VARCHAR2(20) := 'JoHn SmItH';-- If we increase the length of NAME, the other variables-- become longer too. upper_name name%TYPE := UPPER(name); lower_name name%TYPE := LOWER(name);

2-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 67: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言

init_name name%TYPE := INITCAP(name);BEGIN NULL;END;/

%TYPE属性を使用して宣言された変数は、データ型指定子を使用して宣言された変数と同じように扱われます。たとえば前述の宣言では、PL/SQL は debitを REAL(7,2)型の変数として扱います。%TYPE属性を使用した宣言には、初期化句も含めることができます。

%TYPE属性は、データベース列を参照する変数を宣言する場合に特に便利です。次の例のように、表や列を参照したり、所有者、表、列を参照することができます。

DECLARE-- If the length of the column ever changes, this code-- will use the new length automatically. the_trigger user_triggers.trigger_name%TYPE;BEGIN NULL;END;/

table_name.column_name.TYPEを使用して変数を宣言する場合、実際のデータ型、および精度、位取り、長さなどの属性を知っておく必要はありません。列のデータベース定義が変更された場合でも、変数のデータ型は実行時にそれに対応して変更されます。

ただし、%TYPE変数は NOT NULL列制約を継承しません。次の例では、データベース列employee_idが NOT NULLとして定義されていても、変数 my_empnoに NULL を代入できます。

DECLARE my_empno employees.employee_id%TYPE;BEGIN my_empno := NULL; -- this worksEND;/

PL/SQL 言語の基礎 2-13

Page 68: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言

%ROWTYPE 属性の使用属性の使用属性の使用属性の使用%ROWTYPE属性は、表(またはビュー)の中の行を表すレコードを与えます。レコードには、表から選択された行全体のデータを格納することも、カーソルまたは強い型指定のカーソル変数でフェッチされた行全体のデータを格納することもできます。

DECLARE-- %ROWTYPE can include all the columns in a table... emp_rec employees%ROWTYPE;-- ...or a subset of the columns, based on a cursor. CURSOR c1 IS SELECT department_id, department_name FROM departments; dept_rec c1%ROWTYPE;-- Could even make a %ROWTYPE with columns from multiple tables. CURSOR c2 IS SELECT employee_id, email, employees.manager_id, location_id FROM employees, departments WHERE employees.department_id = departments.department_id; join_rec c2%ROWTYPE;BEGIN-- We know EMP_REC can hold a row from the EMPLOYEES table. SELECT * INTO emp_rec FROM employees WHERE ROWNUM < 2;-- We can refer to the fields of EMP_REC using column names-- from the EMPLOYEES table. IF emp_rec.department_id = 20 AND emp_rec.last_name = 'JOHNSON' THEN emp_rec.salary := emp_rec.salary * 1.15; END IF;END;/

行の中の列と、それに対応するレコード中のフィールドは、同じ名前と同じデータ型を持ちます。ただし、%ROWTYPEレコードのフィールドは NOT NULL列制約を継承しません。

集計代入集計代入集計代入集計代入%ROWTYPE宣言に初期化句を含めることはできませんが、レコード中のすべてのフィールドに一度に値を代入する方法があります。レコードの宣言で同じ表またはカーソルが参照されている場合は、あるレコードを別のレコードに代入できます。たとえば、次の代入は有効です。

DECLARE dept_rec1 departments%ROWTYPE; dept_rec2 departments%ROWTYPE; CURSOR c1 IS SELECT department_id, location_id FROM departments; dept_rec3 c1%ROWTYPE;BEGIN dept_rec1 := dept_rec2; -- allowed-- dept_rec2 refers to a table, dept_rec3 refers to a cursor

2-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 69: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言

-- dept_rec2 := dept_rec3; -- not allowedEND;/

次の例に示すように、SELECT文または FETCH文を使用して列の値のリストをレコードに代入できます。列名の順番は、CREATE TABLE文または CREATE VIEW文で定義された順番である必要があります。

DECLARE dept_rec departments%ROWTYPE;BEGIN SELECT * INTO dept_rec FROM departments WHERE department_id = 30 and ROWNUM < 2;END;/

ただし、レコード型のコンストラクタが存在しない場合は、代入文を使用して列の値のリストをレコードに代入できません。

エイリアシングの使用エイリアシングの使用エイリアシングの使用エイリアシングの使用%ROWTYPE属性と関連のあるカーソルからフェッチされた選択リスト項目は、単純名を持つ必要があります。また、選択リスト項目が式の場合は別名を持つ必要があります。次の例では、complete_nameという別名を使用して 2 つの列の連結を表しています。

BEGIN-- We assign an alias (COMPLETE_NAME) to the expression value, because-- it has no column name. FOR item IN ( SELECT first_name || ' ' || last_name complete_name FROM employees WHERE ROWNUM < 11 ) LOOP-- Now we can refer to the field in the record using this alias. dbms_output.put_line('Employee name: ' || item.complete_name); END LOOP;END;/

PL/SQL 言語の基礎 2-15

Page 70: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のネーミング規則

宣言の制限宣言の制限宣言の制限宣言の制限PL/SQL では前方参照ができません。宣言文などの他の文で変数または定数を参照するときは、事前に宣言する必要があります。

PL/SQL ではサブプログラムの前方宣言が可能です。詳細は、8-7 ページの「ネストしたPL/SQL サブプログラムの宣言」を参照してください。

言語によっては、同一のデータ型の複数の変数の並びを一度に宣言できます。ただし、PL/SQL ではそれができません。各変数を次のように別々に宣言する必要があります。

DECLARE-- Multiple declarations not allowed.-- i, j, k, l SMALLINT;-- Instead, declare each separately. i SMALLINT; j SMALLINT;-- To save space, you can declare more than one on a line. k SMALLINT; l SMALLINT;BEGIN NULL;END;/

PL/SQL のネーミング規則のネーミング規則のネーミング規則のネーミング規則定数、変数、カーソル、カーソル変数、例外、プロシージャ、ファンクション、パッケージなどの PL/SQL プログラム項目には、いずれも同じネーミング規則が適用されます。名前には単純名、修飾名、リモート名または修飾リモート名があります。たとえば、プロシージャ名 raise_salaryは次のように使用できます。

raise_salary(...); -- simpleemp_actions.raise_salary(...); -- qualifiedraise_salary@newyork(...); -- remoteemp_actions.raise_salary@newyork(...); -- qualified and remote

1 番目の例ではプロシージャ名をそのまま使用しています。2 番目の例では、プロシージャが emp_actionsという名前のパッケージに格納されているため、ドット表記法を使用して名前を修飾する必要があります。3 番目の例では、プロシージャがリモート・データベースに格納されているため、リモート・アクセスのインジケータ(@)を使用してデータベース・リンク newyorkを参照しています。4 番目の例では、プロシージャ名を修飾し、データベース・リンクの参照も行っています。

2-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 71: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のネーミング規則

シノニムシノニムシノニムシノニム

シノニムを作成し、表、順序、ビュー、スタンドアロン・サブプログラム、パッケージ、オブジェクト型などのリモート・スキーマ・オブジェクトに関する位置の透過性を提供できます。ただし、サブプログラムやパッケージの中で宣言された項目については、シノニムを作成できません。これには、定数、変数、カーソル、カーソル変数、例外およびパッケージ化されたサブプログラムが該当します。

有効範囲有効範囲有効範囲有効範囲

同じ有効範囲の中では、宣言されたすべての識別子が他と重複しないものである必要があります。そのため、変数と定数はデータ型が異なる場合でも同じ名前を共有できません。次の例では、2 番目の宣言は誤りです。

DECLARE valid_id BOOLEAN; valid_id VARCHAR2(5); -- not allowed, duplicate identifierBEGIN-- The error occurs when the identifier is referenced, not-- in the declaration part. valid_id := FALSE;END;/

識別子に適用される有効範囲規則については、2-19 ページの「PL/SQL の識別子の有効範囲と可視性」を参照してください。

大大大大 / 小文字の区別小文字の区別小文字の区別小文字の区別定数、変数およびパラメータの名前では、すべての識別子と同様に大 / 小文字が区別されません。たとえば、PL/SQL は次の名前を同じものとみなします。

DECLARE zip_code INTEGER; Zip_Code INTEGER; -- duplicate identifier, despite Z/z case differenceBEGIN zip_code := 90120; -- causes error because of duplicate identifiersEND;/

名前解決名前解決名前解決名前解決潜在的にあいまいな SQL 文では、データベース列の名前はローカル変数名および仮パラメータ名より優先されます。たとえば、同じ名前の変数と列の両方が 1 つの WHERE 句で使用された場合、SQL は両方とも列を参照するとみなします。

PL/SQL 言語の基礎 2-17

Page 72: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のネーミング規則

重複を避けるため、ローカル変数と仮パラメータの名前に接頭辞を追加するか、ブロック・ラベルを使用して参照を修飾します。

CREATE TABLE employees2 AS SELECT last_name FROM employees;

<<MAIN>>DECLARE last_name VARCHAR2(10) := 'King'; my_last_name VARCHAR2(10) := 'King';BEGIN-- Deletes everyone, because both LAST_NAMEs refer to the column DELETE FROM employees2 WHERE last_name = last_name; dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.'); ROLLBACK;-- OK, column and variable have different names DELETE FROM employees2 WHERE last_name = my_last_name; dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.'); ROLLBACK;-- OK, block name specifies that 2nd LAST_NAME is a variable DELETE FROM employees2 WHERE last_name = main.last_name; dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.'); ROLLBACK;END;/

DROP TABLE employees2;

次の例では、ローカル変数と仮パラメータへの参照を、サブプログラム名を使用して修飾しています。

DECLARE FUNCTION dept_name (department_id IN NUMBER) RETURN departments.department_name%TYPE IS department_name departments.department_name%TYPE; BEGIN-- DEPT_NAME.DEPARTMENT_NAME specifies the local variable-- instead of the table column SELECT department_name INTO dept_name.department_name FROM departments WHERE department_id = dept_name.department_id; RETURN department_name; END;

BEGIN FOR item IN (SELECT department_id FROM departments) LOOP dbms_output.put_line('Department: ' || dept_name(item.department_id));

2-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 73: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の識別子の有効範囲と可視性

END LOOP;END;/

名前解決の詳細は、付録 D を参照してください。

PL/SQL の識別子の有効範囲と可視性の識別子の有効範囲と可視性の識別子の有効範囲と可視性の識別子の有効範囲と可視性識別子に対する参照は、その有効範囲と可視性に従って解決されます。識別子の有効範囲とは、その識別子の参照が可能な、プログラム・ユニット(ブロック、サブプログラムまたはパッケージ)の領域です。識別子は、未修飾の名前で識別子を参照できる領域からのみ、可視の状態になっています。図 2-1 は、xという名前の変数の有効範囲と可視性を示します。この変数は囲みブロックで宣言されてからサブブロックで再宣言されます。

ある PL/SQL ブロックで宣言された識別子は、そのブロックに対してはローカルであり、そのサブブロックすべてに対してはグローバルです。グローバル識別子がサブブロックの中で再宣言されると、両方の識別子が有効範囲内にあることになります。ただし、サブブロックの中でグローバル識別子を参照する場合は修飾名が必要になるため、可視であるのはローカル識別子のみです。

同じブロックで識別子を 2 度宣言できませんが、同じ識別子を 2 つの異なるブロックで宣言できます。識別子が表す 2 つの項目は区別され、一方を変更しても他方には影響がありません。ただし、あるブロックから、同じレベルの他のブロックで宣言されている識別子への参照はできません。そのような識別子は、そのブロックに対してローカルでもグローバルでもないためです。

PL/SQL 言語の基礎 2-19

Page 74: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の識別子の有効範囲と可視性

図図図図 2-1 有効範囲と可視性有効範囲と可視性有効範囲と可視性有効範囲と可視性

次の例は、有効範囲規則を示すものです。あるサブブロックで宣言された識別子は、別のサブブロックで参照できないことに注意してください。これは、あるブロックと同じレベルでネストされた他のブロックで宣言された識別子を、そのブロックで参照できないためです。

DECLARE a CHAR; b REAL;BEGIN -- identifiers available here: a (CHAR), b DECLARE a INTEGER; c REAL; BEGIN -- identifiers available here: a (INTEGER), b, c END; DECLARE d REAL; BEGIN -- identifiers available here: a (CHAR), b, d

2-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 75: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の識別子の有効範囲と可視性

END; -- identifiers available here: a (CHAR), bEND;/

グローバル識別子はサブブロックで再宣言でき、その場合はローカルな宣言が優先され、サブブロックでは、修飾名を使用しないとグローバル識別子を参照できません。外側のブロックのラベルを修飾子として使用できます。

<<outer>>DECLARE birthdate DATE;BEGIN DECLARE birthdate DATE; BEGIN ... IF birthdate = outer.birthdate THEN ... END; ...END;/

また、次の例に示すように、外側のサブプログラムの名前を修飾子として使用できます。

PROCEDURE check_credit (...) IS rating NUMBER; FUNCTION valid (...) RETURN BOOLEAN IS rating NUMBER; BEGIN ... IF check_credit.rating < 3 THEN ... END;BEGIN ...END;/

ただし、同一の有効範囲内でラベルとサブプログラムを同じ名前にすることはできません。

PL/SQL 言語の基礎 2-21

Page 76: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

変数への値の代入

変数への値の代入変数への値の代入変数への値の代入変数への値の代入変数に値を代入する場合は、代入文を使用します。たとえば、次の文では変数 bonusの古い値を上書きして、新しい値を代入します。

bonus := salary * 0.15;

変数を明示的に初期化しないかぎり、その値は未定義(NULL)です。

変数と定数は、ブロックまたはサブプログラムに入るたびに初期化されます。デフォルトでは、変数は NULLに初期化されます。

DECLARE counter INTEGER;BEGIN-- COUNTER is initially NULL, so 'COUNTER + 1' is also null. counter := counter + 1; IF counter IS NULL THEN dbms_output.put_line('Sure enough, COUNTER is NULL not 1.'); END IF;END;/

予期しない結果を避けるため、値を代入する前に変数を参照しないでください。

代入演算子の後に続く式は、複雑なものでもかまいませんが、そのデータ型は変数のデータ型と同じか、または変数のデータ型に変換できるものである必要があります。

ブール値の代入ブール値の代入ブール値の代入ブール値の代入ブール変数に代入できるのは、値 TRUE、FALSEおよび NULLのみです。関係演算子を使用して、これらのリテラル値、または比較などの式を代入できます。

DECLARE done BOOLEAN; -- DONE is initially NULL counter NUMBER := 0;BEGIN done := FALSE; -- Assign a literal value WHILE done != TRUE -- Compare to a literal value LOOP counter := counter + 1; done := (counter > 500); -- If counter > 500, DONE = TRUE END LOOP;END;/

2-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 77: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

SQL 問合せ結果の問合せ結果の問合せ結果の問合せ結果の PL/SQL 変数への代入変数への代入変数への代入変数への代入SELECT文を使用しても変数に値を代入できます。選択リストの項目ごとに、対応する型互換の変数が INTOリストに存在している必要があります。次に例を示します。

DECLARE emp_id employees.employee_id%TYPE := 100; emp_name employees.last_name%TYPE; wages NUMBER(7,2);BEGIN SELECT last_name, salary + (salary * nvl(commission_pct,0)) INTO emp_name, wages FROM employees WHERE employee_id = emp_id; dbms_output.put_line('Employee ' || emp_name || ' might make ' || wages);END;/

SQL にはブール型がないため、列の値を選択してブール変数に代入できません。

PL/SQL の式および比較の式および比較の式および比較の式および比較式はオペランドと演算子を使用して作成します。オペランドオペランドオペランドオペランドとは、変数、定数、リテラルまたはファンクション・コールのことで、式の中の値はオペランドを使用して表現します。単純な算術式の例を次に示します。

-X / 2 + 3

否定演算子(-)のような単項演算子は、1 つのオペランドに対して作用します。除算演算子(/)のようなバイナリ演算子は、2 つのオペランドに対して作用します。PL/SQL には 3項演算子はありません。

も単純な式は変数 1 つで構成され、その変数の値が式の値になります。PL/SQL は、演算子が指定する方法でオペランドの値を組み合せて、式を評価します。式は常に 1 つの値を戻します。PL/SQL は、式の内容と、式が使用されているコンテキストに基づいてこの値のデータ型を決定します。

PL/SQL 言語の基礎 2-23

Page 78: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

演算子の優先順位演算子の優先順位演算子の優先順位演算子の優先順位式の中の演算は、優先順位に応じて特定の順序で実行されます。表 2-1 に、デフォルトでの演算の順序を上から順に示します。

優先順位が高い演算子が先に適用されます。たとえば、次の 2 つの式の結果はどちらも 8 になります。これは、除算が加算よりも優先順位が高いためです。同じ優先順位の演算子は、特に順序を考慮せずに適用されます。

5 + 12 / 412 / 4 + 5

カッコを使用すると、評価の順序を制御できます。たとえば、次の式ではカッコで演算子のデフォルトの優先順位が上書きされるため、式の結果は 11 ではなく 7 になります。

(8 + 6) / 2

次の例では、 も深くネストされた副式が必ず 初に評価されるため、除算の前に減算が実行されます。

100 + (20 / 5 + (7 - 3))

次の例のように、カッコが不要な場合でも、わかりやすくするために自由にカッコを使用できます。

(salary * 0.05) + (commission * 0.25)

表表表表 2-1 演算の順序演算の順序演算の順序演算の順序

演算子演算子演算子演算子 演算演算演算演算

** 指数

+、- 恒等、否定

*、/ 乗算、除算

+、-、|| 加算、減算、連結

=、<、>、<=、>=、<>、!=、~=、^=、IS NULL、LIKE、BETWEEN、IN

比較

NOT 論理否定

AND 論理積

OR 論理和

2-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 79: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

論理演算子論理演算子論理演算子論理演算子論理演算子 AND、ORおよび NOTは、表 2-2 に示す 3 値論理に従います。ANDと ORはバイナリ演算子、NOTは単項演算子です。

真理値表からわかるように、ANDは、オペランドの両方が TRUE の場合にのみ TRUEを戻します。一方、ORは、オペランドの片方が TRUE ならば TRUEを戻します。NOTはオペランドの反対の値(論理否定)を戻します。たとえば、NOT TRUEは FALSEを戻します。

NULL は値を持たないため、NOT NULLは NULLを戻します。NULL を伴う式で予測不可能な結果が発生しないように注意してください。2-34 ページの「比較文と条件文での NULLの扱い」を参照してください。

評価の順序評価の順序評価の順序評価の順序

カッコを使用して評価の順序を指定しない場合は、演算子の優先順位によって順序が決定されます。次の式を比べてみてください。

NOT (valid AND done) | NOT valid AND done

ブール変数 validと doneがどちらも値 FALSEを持つ場合、1 番目の式の結果は TRUEになります。ただし、2 番目の式では NOTが ANDより優先されるため、結果は FALSEになります。したがって、2 番目の式は次の式と等価になります。

(NOT valid) AND done

表表表表 2-2 論理真理値表論理真理値表論理真理値表論理真理値表

X y x AND y x OR y NOT x

TRUE TRUE TRUE TRUE FALSE

TRUE FALSE FALSE TRUE FALSE

TRUE NULL NULL TRUE FALSE

FALSE TRUE FALSE TRUE TRUE

FALSE FALSE FALSE FALSE TRUE

FALSE NULL FALSE NULL TRUE

NULL TRUE NULL TRUE NULL

NULL FALSE FALSE NULL NULL

NULL NULL NULL NULL NULL

PL/SQL 言語の基礎 2-25

Page 80: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

次の例では、validの値が FALSEである場合、doneの値とは関係なく式全体の結果がFALSEになることに注意してください。

valid AND done

同様に、次の例では、validの値が TRUEである場合に、doneの値とは関係なく式全体の結果が TRUEになります。

valid OR done

短絡評価短絡評価短絡評価短絡評価

論理式を評価するときに、PL/SQL では短絡評価を使用します。これによって、PL/SQL は結果が判別できた時点でただちに式の評価を停止します。そのため、評価を続ければエラーになるような式でも書くことができます。次の OR式で考えてみます。

DECLARE on_hand INTEGER := 0; on_order INTEGER := 100;BEGIN-- Does not cause divide-by-zero error; evaluation stops after 1st expr. IF (on_hand = 0) OR ((on_order / on_hand) < 5) THEN dbms_output.put_line('There are no more widgets left!'); END IF;END;/

on_handの値が 0(ゼロ)の場合、左のオペランドは TRUEになるため、PL/SQL は右のオペランドを評価しません。OR演算子を適用する前に両方のオペランドを評価した場合には、右のオペランドは 0 による除算エラーになります。

比較演算子比較演算子比較演算子比較演算子

比較演算子は式と式を比較します。結果は常に TRUE、FALSE、NULL のいずれかです。比較演算子は、一般に、SQL DML 文の WHEREと、条件制御文の中で使用します。異なる型の比較の例を次に示します。

DECLARE PROCEDURE assert(assertion VARCHAR2, truth BOOLEAN) IS BEGIN IF truth IS NULL THEN dbms_output.put_line('Assertion ' || assertion || ' is unknown (NULL)'); ELSIF truth = TRUE THEN dbms_output.put_line('Assertion ' || assertion || ' is TRUE'); ELSE dbms_output.put_line('Assertion ' || assertion || ' is FALSE'); END IF; END;

2-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 81: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

BEGIN assert('2 + 2 = 4', 2 + 2 = 4); assert('10 > 1', 10 > 1); assert('10 <= 1', 10 <= 1); assert('5 BETWEEN 1 AND 10', 5 BETWEEN 1 AND 10); assert('NULL != 0', NULL != 0); assert('3 IN (1,3,5)', 3 IN (1,3,5)); assert('''A'' < ''Z''', 'A' < 'Z'); assert('''baseball'' LIKE ''%all%''', 'baseball' LIKE '%all%'); assert('''suit'' || ''case'' = ''suitcase''', 'suit' || 'case' = 'suitcase');END;/

関係演算子関係演算子関係演算子関係演算子

IS NULL 演算子演算子演算子演算子

IS NULL演算子は、オペランドが NULL の場合はブール値 TRUEを、NULL ではない場合は FALSEを戻します。NULL が関係する比較は、常に結果が NULLになります。値がNULL かどうかをテストするには、次の文を使用します。

IF variable IS NULL THEN ...

LIKE 演算子演算子演算子演算子

LIKE演算子を使用すると、文字、文字列または CLOB値をパターンと比較できます。大 /小文字が区別されます。LIKEは、パターンが一致すればブール値 TRUEを、一致しなければ FALSEを戻します。

演算子演算子演算子演算子 意味意味意味意味

= 等しい

<>、!=、~=、^= 等しくない

< より小さい

> より大きい

<= より小さいか、等しい

>= より大きいか、等しい

PL/SQL 言語の基礎 2-27

Page 82: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

LIKEを使用してパターンを比較するために、ワイルドカードワイルドカードワイルドカードワイルドカードと呼ばれる 2 つの特殊な目的の文字を使用できます。アンダースコア(_)は 1 つの文字を表します。パーセント記号

(%)は 0(ゼロ)個以上の文字を表します。たとえば、enameの値が 'JOHNSON'の場合、次の式は TRUE になります。

ename LIKE 'J%S_N'

パーセント記号やアンダースコアを検索するには、エスケープ文字を定義して、パーセント記号またはアンダースコアの前にそのエスケープ文字を挿入します。次の例では、バックスラッシュをエスケープ文字として使用しているため、文字列中のパーセント記号はワイルドカードとしての役割は果たしません。

IF sale_sign LIKE '50\% off!' ESCAPE '\' THEN...

BETWEEN 演算子演算子演算子演算子

BETWEEN演算子は、ある値が、指定された範囲に含まれているかどうかをテストします。つまり、「下限以上、上限以下」という意味を持ちます。たとえば、次の式は FALSE です。

45 BETWEEN 38 AND 44

IN 演算子演算子演算子演算子

IN演算子は、セット・メンバーシップを調べます。つまり、集合の「いずれかのメンバーと等しい」かどうかがテストされます。集合には NULL が含まれていてもかまいませんが、NULL は無視されます。たとえば、次の式は、値が集合に含まれるかどうかを調べます。

letter IN ('a','b','c')

この条件を反転する場合は注意が必要です。次の形式の式について考えます。

value NOT IN set

この式では、集合に NULL が含まれていると FALSEになります。

連結演算子連結演算子連結演算子連結演算子

連結演算子(||)は、文字列(CHAR、VARCHAR2、CLOBまたはそれと同等の Unicode で使用可能な型)を他の文字列に連結します。使用例を次に示します。

'suit' || 'case'

これは、次の行を戻します。

'suitcase'

両方のオペランドがデータ型 CHARを持つ場合、連結演算子は CHAR型の値を戻します。一方のオペランドが CLOB値を持つ場合、連結演算子は一時的な CLOB を戻します。それ以外の場合は、VARCHAR2型の値を戻します。

2-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 83: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

ブール式ブール式ブール式ブール式PL/SQL では、SQL 文の中でもプロシージャ文の中でも、変数と定数を比較できます。これらの比較はブール式と呼ばれ、関係演算子で区切られた単純式またはコンポジット式で構成されます。ブール式は一般に論理演算子 AND、ORおよび NOTで結合されます。ブール式の結果は常に、TRUE、FALSE、NULLのいずれかになります。

SQL 文の中でブール式を使用して、表の中の文が影響を与える列を指定できます。プロシージャ文では、条件制御の基盤としてブール式が使用されます。ブール式には、算術式、文字式および日付式の 3 種類があります。

ブール算術式ブール算術式ブール算術式ブール算術式

関係演算子を使用して数値を比較し、等しいか等しくないかを判定できます。比較は量によるものです。つまり、片方の数値がより大きな量を表す場合、その数値はより大きいとみなされます。たとえば、次のような代入文があるとします。

number1 := 75;number2 := 70;

次の式は TRUE になります。

number1 > number2

ブール文字式ブール文字式ブール文字式ブール文字式

文字値を比較して、等しいか等しくないかを判定できます。デフォルトでは、比較は文字列の各バイトのバイナリ値に基づいて行われます。

たとえば、次のような代入文があるとします。

string1 := 'Kathy';string2 := 'Kathleen';

次の式は TRUE になります。

string1 > string2

初期化パラメータ NLS_COMP=ANSIを設定すると、NLS_SORT初期化パラメータで識別される照合順番を比較に使用できます。照合順番照合順番照合順番照合順番とは、特定の範囲の数値コードが個々の文字に対応しているキャラクタ・セットの内部的な順序のことです。内部的な順番を表す数値が他方の文字より大きい場合、その文字値はより大きいとみなされます。この種の文字が照合順番に使用される場所については、言語ごとに規則が異なる場合があります。たとえば、アクセント記号が付いた文字のソート順序は、バイナリ値が同じであってもデータベース・キャラクタ・セットに応じて異なることがあります。

PL/SQL 言語の基礎 2-29

Page 84: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

NLS_SORTパラメータの値によっては、大 / 小文字およびアクセント記号の有無を区別しない比較を実行できます。大 / 小文字を区別しない比較では、オペランドの文字の大 / 小文字が異なる場合でも TRUE が戻されます。アクセント記号の有無を区別しない比較は、大 / 小文字を区別せず、オペランドのアクセント記号またはデリミタ文字が異なる場合でも TRUEが戻されます。たとえば、大 / 小文字を区別しない比較では、'True'と 'TRUE'の文字値は同じであるとみなされ、'Cooperate'、'Co-Operate'および 'coöperate'の文字値もすべて同じであるとみなされます。大 / 小文字を区別せずに比較するには、NLS_SORTパラメータの通常の値の末尾に _CIを付けます。アクセント記号の有無を区別せずに比較するには、NLS_SORTの値の末尾に _AIを付けます。

文字値を比較する場合には、ベース型 CHARと VARCHAR2の間にある意味上の違いを考慮する必要があります。詳細は、付録 B を参照してください。

多くの型は文字型に変換できます。たとえば、CLOB変数を使用して比較、代入および他の文字操作を実行できます。実行可能な変換の詳細は、3-6 ページの「PL/SQL の文字型と文字列型」を参照してください。

ブール日付式ブール日付式ブール日付式ブール日付式日付も比較できます。比較は時系列によってなされます。つまり、片方の日付がより新しければ、その日付はより大きいとみなされます。たとえば、次のような代入文があるとします。

date1 := '01-JAN-91';date2 := '31-DEC-90';

次の式は TRUE になります。

date1 > date2

PL/SQL ブール式のガイドラインブール式のガイドラインブール式のガイドラインブール式のガイドライン

� 一般に、実数を比較して等しいかどうかを判定することはお薦めしません。実数は近似値として格納されます。たとえば、次のような IF条件は TRUEにならない可能性があります。

DECLARE fraction BINARY_FLOAT := 1/3;BEGIN IF fraction = 11/33 THEN dbms_output.put_line('Fractions are equal (luckily!)'); END IF;END;/

2-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 85: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

� 比較する場合は、カッコを使用することをお薦めします。たとえば次の式で、100 < taxはブール値になりますが、これは数値 500 と比較できないため、この式は無効です。

100 < tax < 500 -- not allowed

これをデバッグすれば、次の式になります。

(100 < tax) AND (tax < 500)

� ブール変数はそれ自身が TRUE または FALSE です。変数をリテラル値の TRUE、FALSEと比較するのではなく、単に変数を条件テストに使用できます。たとえば、次のコマンドは同じ意味を持ちます。

DECLARE done BOOLEAN ;BEGIN-- Each WHILE loop is equivalent done := FALSE; WHILE done = FALSE LOOP done := TRUE; END LOOP;

done := FALSE; WHILE NOT (done = TRUE) LOOP done := TRUE; END LOOP;

done := FALSE; WHILE NOT done LOOP done := TRUE; END LOOP;END;/

� CLOB値を比較演算子または LIKEや BETWEENなどのファンクションとともに使用すると、一時的な LOB が作成されます。一時表領域がこのような一時的な LOB を処理できる大きさかどうかを確認する必要があります。

PL/SQL 言語の基礎 2-31

Page 86: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

CASE 式式式式CASE式は、1 つ以上の選択肢から結果を選択して戻します。CASE式が複数の行にわたるブロックを含む場合でも、CASE 式は代入やプロシージャ・コールなどの大きい文の一部を構成する 1 つの式です。

CASE式は選択子選択子選択子選択子を使用します。選択子は、その値によって戻す代替アクションが決まる式です。CASE式の書式は、次のとおりです。

CASE selector WHEN expression1 THEN result1 WHEN expression2 THEN result2 ... WHEN expressionN THEN resultN [ELSE resultN+1]END

選択子の後に 1 つ以上の WHEN句があり、各句が順番にチェックされます。選択子の値によって、どの句が評価されるかが決定されます。選択子の値と 初に一致した WHEN句によって結果値が決定され、後続の WHEN句は評価されません。次に例を示します。

DECLARE grade CHAR(1) := 'B'; appraisal VARCHAR2(20);BEGIN appraisal := CASE grade WHEN 'A' THEN 'Excellent' WHEN 'B' THEN 'Very Good' WHEN 'C' THEN 'Good' WHEN 'D' THEN 'Fair' WHEN 'F' THEN 'Poor' ELSE 'No such grade' END; dbms_output.put_line('Grade ' || grade || ' is ' || appraisal);END;/

オプションの ELSE句の機能は、IF文の ELSE句に似ています。選択子の値が WHEN句のオプションの 1 つでなければ、ELSE句が実行されます。ELSE句が指定されておらず、一致する WHEN句がなければ、式は NULLを戻します。

CASE式のかわりに、CASE文を使用して WHEN句に PL/SQL ブロック全体を使用できます。詳細は、4-4 ページの「CASE 文の使用」を参照してください。

2-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 87: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

検索検索検索検索 CASE 式式式式PL/SQL は検索 CASE式も提供します。検索 CASE式を使用すると、1 つの式を様々な値と比較するのではなく、異なる条件をテストできます。次の形式の式について考えます。

CASE WHEN search_condition1 THEN result1 WHEN search_condition2 THEN result2 ... WHEN search_conditionN THEN resultN [ELSE resultN+1]END;

検索 CASE式には選択子はありません。各 WHEN句にはブール値を生成する検索条件が含まれており、単一の WHEN句で異なる変数または複数の条件をテストできます。次に例を示します。

DECLARE grade CHAR(1) := 'B'; appraisal VARCHAR2(120); id NUMBER := 8429862; attendance NUMBER := 150; min_days CONSTANT NUMBER := 200;FUNCTION attends_this_school(id NUMBER) RETURN BOOLEAN IS BEGIN RETURN TRUE; END;BEGIN appraisal := CASE WHEN attends_this_school(id) = FALSE THEN 'N/A - Student not enrolled'-- Have to put this condition early to detect-- good students with bad attendance WHEN grade = 'F' OR attendance < min_days THEN 'Poor (poor performance or bad attendance)' WHEN grade = 'A' THEN 'Excellent' WHEN grade = 'B' THEN 'Very Good' WHEN grade = 'C' THEN 'Good' WHEN grade = 'D' THEN 'Fair' ELSE 'No such grade' END; dbms_output.put_line('Result for student ' || id || ' is ' || appraisal);END;/

PL/SQL 言語の基礎 2-33

Page 88: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

検索条件は順番に評価されます。各検索条件のブール値によって、どの WHEN句が実行されるかが決定されます。検索条件が TRUEになると、その WHEN句が実行されます。WHEN句が 1 つでも実行された後は、後続の検索条件は評価されません。TRUEになる検索条件がなければ、オプションの ELSE句が実行されます。WHEN句が実行されず、ELSE句が指定されていなければ、式の値は NULLとなります。

比較文と条件文での比較文と条件文での比較文と条件文での比較文と条件文での NULL の扱いの扱いの扱いの扱いNULL を使用する場合は、次の規則を念頭に置くことで、問題の発生を未然に防ぐことができます。

� NULL が関係する比較は、常に結果が NULLになります。

� 論理演算子 NOTを NULL 値に適用すると NULLが戻ります。

� 条件制御文において条件が NULLになる場合、関連する一連の文は実行されません。

� 単純な CASE文中の式または CASE式が NULLになる場合は、WHEN NULLを使用して一致させることができません。この場合は、検索 CASE 構文を使用して WHEN expression IS NULLをテストする必要があります。

次の例では、xと yが等しくないために一連の文(sequence_of_statements)が実行されることが予測されます。ただし、NULL は予測不可能です。そのため、xと yが等しいかどうかは不明です。したがって、IF条件は NULLになり、一連の文は実行されずにバイパスされます。

DECLARE x NUMBER := 5; y NUMBER := NULL;BEGIN IF x != y THEN -- yields NULL, not TRUE dbms_output.put_line('x != y'); -- not executed ELSIF x = y THEN -- also yields NULL dbms_output.put_line('x = y'); ELSE dbms_output.put_line('Can''t tell if x and y are equal or not...'); END IF;END;/

次の例では、aと bが等しいために一連の文が実行されると予測されます。ただし、等号条件が成立するかどうかは不明であるため、IF条件は NULLになり、一連の文は実行されずにバイパスされます。

DECLARE a NUMBER := NULL; b NUMBER := NULL;BEGIN IF a = b THEN -- yields NULL, not TRUE

2-34 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 89: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

dbms_output.put_line('a = b'); -- not executed ELSIF a != b THEN -- yields NULL, not TRUE dbms_output.put_line('a != b'); -- not executed ELSE dbms_output.put_line('Can''t tell if two NULLs are equal'); END IF;END;/

NULL とととと NOT 演算子演算子演算子演算子論理演算子 NOTを NULL 値に適用すると NULLが戻ることに注意してください。このため、次の 2 つの文は必ずしも等価ではありません。

IF x > y THEN | IF NOT x > y THEN high := x; | high := y;ELSE | ELSE high := y; | high := x;END IF; | END IF;

IF条件が FALSEまたは NULLになると、ELSE句内の一連の文が実行されます。xと yのどちらも NULL ではない場合、両方の IF文で同じ値が highに代入されます。ただし、xと yのどちらかが NULL の場合、1 番目の IF文は yの値を highに代入しますが、2 番目の IF文は xの値を highに代入します。

NULL と長さと長さと長さと長さ 0(ゼロ)の文字列(ゼロ)の文字列(ゼロ)の文字列(ゼロ)の文字列

PL/SQL は長さが 0(ゼロ)の文字値をすべて NULL とみなします。これには文字関数やブール式によって戻された値が含まれます。たとえば、次の文ではターゲットの変数にNULL を代入します。

DECLARE null_string VARCHAR2(80) := TO_CHAR(''); address VARCHAR2(80); zip_code VARCHAR2(80) := SUBSTR(address, 25, 0); name VARCHAR2(80); valid BOOLEAN := (name != '');BEGIN NULL;END;/

NULL 文字列かどうかをテストする場合は、次のように IS NULL演算子を使用してください。

IF my_string IS NULL THEN ...

PL/SQL 言語の基礎 2-35

Page 90: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

NULL と連結演算子と連結演算子と連結演算子と連結演算子連結演算子は NULL オペランドを無視します。使用例を次に示します。

'apple' || NULL || NULL || 'sauce'

これは、次の行を戻します。

'applesauce'

組込みファンクションの引数としての組込みファンクションの引数としての組込みファンクションの引数としての組込みファンクションの引数としての NULL組込みファンクションに引数 NULL が渡されると、次に示す場合を除いて NULL が戻されます。

ファンクション DECODEは、先頭の引数を 1 つまたは複数の検索式と比較します。検索式は結果式と対になっています。検索式や結果式は NULL の場合があります。検索に成功すると、対応する結果が戻されます。次の例で、列 ratingが NULL ならば、DECODEは値1000 を戻します。

DECLARE the_manager VARCHAR2(40); name employees.last_name%TYPE;BEGIN-- NULL is a valid argument to DECODE. In this case, manager_id is null-- and the DECODE function returns 'nobody'. SELECT DECODE(manager_id, NULL, 'nobody', 'somebody'), last_name INTO the_manager, name FROM employees WHERE employee_id = 100; dbms_output.put_line(name || ' is managed by ' || the_manager);END;/

先頭の引数が NULL の場合、ファンクション NVLは 2 番目の引数の値を戻します。次の例では、問合せで指定された列が NULL の場合、ファンクションは値 -1 を戻し、従業員が存在しないことを出力に示します。

DECLARE the_manager employees.manager_id%TYPE; name employees.last_name%TYPE;BEGIN-- NULL is a valid argument to NVL. In this case, manager_id is null-- and the NVL function returns -1. SELECT NVL(manager_id, -1), last_name INTO the_manager, name FROM employees WHERE employee_id = 100; dbms_output.put_line(name || ' is managed by employee #' || the_manager);END;/

2-36 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 91: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の式および比較

2 番目の引数が NULL の場合、ファンクション REPLACEはオプションの 3 番目の引数が存在するかどうかにかかわらず、1 番目の引数の値を戻します。たとえば、次の REPLACEのコールは、OLD_STRINGの値を変更しません。

DECLARE string_type VARCHAR2(60); old_string string_type%TYPE := 'Apples and oranges'; my_string string_type%TYPE := 'more apples';-- NULL is a valid argument to REPLACE, but does not match-- anything so no replacement is done. new_string string_type%TYPE := REPLACE(old_string, NULL, my_string);BEGIN dbms_output.put_line('Old string = ' || old_string); dbms_output.put_line('New string = ' || new_string);END;/

3 番目の引数が NULL ならば、REPLACEは、1 番目の引数から 2 番目の引数をすべて削除したものを戻します。たとえば、次の REPLACEのコールは、DASHED_STRINGのダッシュを別の文字で置き換えるのではなく、削除します。

DECLARE string_type VARCHAR2(60); dashed string_type%TYPE := 'Gold-i-locks';-- When the substitution text for REPLACE is NULL,-- the text being replaced is deleted. name string_type%TYPE := REPLACE(dashed, '-', NULL);BEGIN dbms_output.put_line('Dashed name = ' || dashed); dbms_output.put_line('Dashes removed = ' || name);END;/

2 番目の引数と 3 番目の引数が NULL の場合、REPLACEは単に 1 番目の引数を戻します。

PL/SQL 言語の基礎 2-37

Page 92: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の組込みファンクションのまとめ

PL/SQL の組込みファンクションのまとめの組込みファンクションのまとめの組込みファンクションのまとめの組込みファンクションのまとめPL/SQL には、データを操作するために役立つ多くの強力なファンクションが用意されています。組込みファンクションは、次のカテゴリに分類できます。

エラー・レポート数値文字データ型変換日付オブジェクト参照その他

表 2-3 に、各カテゴリのファンクションを示します。エラー・レポート・ファンクションの説明は、第 13 章を参照してください。その他のファンクションの説明は、『Oracle Database SQL リファレンス』を参照してください。

SQL 文の中では、エラー報告ファンクション SQLCODEと SQLERRMを除くすべてのファンクションを使用できます。また、オブジェクト参照ファンクション DEREF、REFおよびVALUEとファンクション DECODE、DUMPおよび VSIZE以外であれば、すべてのファンクションをプロシージャ文で使用できます。

SQL 集計関数(AVGや COUNTなど)と SQL 分析関数(CORRや LAGなど)は PL/SQL に組み込まれていませんが、SQL 文に使用できます(ただし、プロシージャ文には使用できません)。

2-38 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 93: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の組込みファンクションのまとめ

表表表表

エエエエ

SQSQ

2-3 組込みファンクション組込みファンクション組込みファンクション組込みファンクション

ラーラーラーラー 数値数値数値数値 文字文字文字文字 変換変換変換変換 日付日付日付日付

オブオブオブオブジェクジェクジェクジェクト参照ト参照ト参照ト参照 その他その他その他その他

LCODELERRM

ABSACOSASINATANATAN2BITANDCEILCOSCOSHEXPFLOORLNLOGMODPOWERREMAINDERROUNDSIGNSINSINHSQRTTANTANHTRUNC

ASCIIASCIISTRCHRCOMPOSECONCATDECOMPOSEINITCAPINSTRINSTR2INSTR4INSTRBINSTRCLENGTHLENGTH2LENGTH4LENGTHBLENGTHCLOWERLPADLTRIMNCHRNLS_INITCAPNLS_LOWERNLSSORTNLS_UPPERREGEXP_INSTRREGEXP_LIKEREGEXP_REPLACEREGEXP_SUBSTRREPLACERPADRTRIMSOUNDEXSUBSTRSUBSTR2SUBSTR4SUBSTRBSUBSTRCTRANSLATETRIMUNISTRUPPER

CHARTOROWIDCONVERTHEXTORAWRAWTOHEXRAWTONHEXROWIDTOCHARTO_BINARY_DOUBLETO_BLOBTO_BINARY_FLOATTO_CHARTO_CLOBTO_DATETO_MULTI_BYTETO_NCHARTO_NCLOBTO_NUMBERTO_SINGLE_BYTE

ADD_MONTHSCURRENT_DATECURRENT_TIMECURRENT_TIMESTAMPDBTIMEZONEEXTRACTFROM_TZLAST_DAYLOCALTIMESTAMPMONTHS_BETWEENNEW_TIMENEXT_DAYNUMTODSINTERVALNUMTOYMINTERVALROUNDSESSIONTIMEZONESYS_EXTRACT_UTCSYSDATESYSTIMESTAMPTO_DSINTERVAL

TO_TIMETO_TIME_TZTO_TIMESTAMPTO_TIMESTAMP_TZTO_YMINTERVALTRUNCTZ_OFFSET

DEREFREFTREATVALUE

BFILENAMECOALESCEDECODEDUMPEMPTY_BLOBEMPTY_CLOBGREATESTLEASTNANVLNLS_CHARSET_DECL_LENNLS_CHARSET_IDNLS_CHARSET_NAMENULLIFNVLSYS_CONTEXTSYS_GUIDUIDUSERUSERENVVSIZE

PL/SQL 言語の基礎 2-39

Page 94: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の組込みファンクションのまとめ

2-40 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 95: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のデー

3

PL/SQL のデータ型のデータ型のデータ型のデータ型

すべての定数、変数およびパラメータは、記憶形式、制約および値の有効範囲を指定するデータ型(または型)を持っています。PL/SQL には、多くの事前定義のデータ型が用意されています。たとえば、整数、浮動小数点、文字、ブール、日付、コレクション、参照およびラージ・オブジェクト(LOB)の各型から選択できます。また、PL/SQL では独自のサブタイプを定義できます。この章では、PL/SQL プログラムで頻繁に使用する基本的な型について説明します。より特化された型については、以降の章を参照してください。

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

� 事前定義された PL/SQL データ型の概要(3-2 ページ)

� PL/SQL サブタイプの概要(3-21 ページ)

� PL/SQL データ型の変換(3-23 ページ)

タ型 3-1

Page 96: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

事前定義された事前定義された事前定義された事前定義された PL/SQL データ型の概要データ型の概要データ型の概要データ型の概要スカラー型には内部コンポーネントがありません。スカラー型は、数値や文字列などの 1 つの値を保持します。

コンポジット型には、配列の要素のような、個別に操作できる内部的な要素があります。

参照型には、他のプログラム項目を指定するポインタという値があります。

LOB型には、LOB ロケータという値があります。この値は、他のデータベース・データとは別に格納されている大きいオブジェクト(テキスト・ブロックや図形イメージなど)の位置を指定します。

図 3-1 に、事前定義された PL/SQL データ型を示します。スカラー型は数値、文字、日付 /時刻、真理値などを格納するデータの種類によって 4 つのグループに分類されます。

図図図図 3-1 組込みデータ型組込みデータ型組込みデータ型組込みデータ型

3-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 97: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

PL/SQL の数値型の数値型の数値型の数値型数値型は、数値データ(整数、実数および浮動小数点数)の格納、量の表現および計算に使用します。

BINARY_INTEGERBINARY_INTEGERデータ型は、符号付き整数を格納するために使用します。値の大きさの範囲は、-2**31 ~ 2**31 です。

BINARY_INTEGER値は、NUMBERの値より小さい記憶域しか必要としません。また、BINARY_INTEGER値の算術演算は NUMBER値の算術演算より高速に処理されます。これらのメリットは、BINARY_INTEGERと PLS_INTEGERの両方にあります。以前のリリースでは PLS_INTEGERの方が高速に処理されたため、古いデータベースで実行するコードでは、これを BINARY_INTEGERのかわりに使用している場合があります。

BINARY_INTEGER サブタイプサブタイプサブタイプサブタイプ ベース型は、サブタイプの導出元となるデータ型です。サブタイプはベース型を制約と結び付け、値のサブセットを定義します。PL/SQL では、次のような BINARY_INTEGERサブタイプがあらかじめ定義されています。

NATURALNATURALNPOSITIVEPOSITIVENSIGNTYPE

サブタイプ NATURALおよび POSITIVEは、整変数をそれぞれ負ではない整数値、または正の整数値に制限する場合に使用します。NATURALNと POSITIVENは、整変数に NULL を代入できないようにします。SIGNTYPEは、整変数を値 -1、0、1 に制限するときに使用します。これは 3 値論理のプログラミングに役立ちます。

BINARY_FLOAT およびおよびおよびおよび BINARY_DOUBLEそれぞれ単精度と倍精度の IEEE 754 形式の単精度浮動小数点数を格納します。これらの型は、主に科学的な高速計算に使用されます。使用方法は、11-24 ページの「PL/SQL での計算集中型プログラムの記述」を参照してください。異なる数値型を受け入れる数学ライブラリを記述する方法は、8-14 ページの「数値型のオーバーロードのガイドライン」を参照してください。

これらの型のリテラルは、末尾に f(BINARY_FLOATの場合)または d(BINARY_DOUBLEの場合)が付きます(たとえば、2.07fや 3.000094d)。

PL/SQL のデータ型 3-3

Page 98: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

これらの型を伴う計算は、例外を呼び出すのではなく、確認が必要な特別な値を生成します。これらの数に発生する可能性があるオーバーフロー、アンダーフローおよびその他の条件を処理するには、BINARY_FLOAT_NAN、BINARY_FLOAT_INFINITY、BINARY_FLOAT_MAX_NORMAL、BINARY_FLOAT_MIN_NORMAL、BINARY_FLOAT_MAX_SUBNORMAL、BINARY_FLOAT_MIN_SUBNORMAL、およびBINARY_DOUBLEで始まる対応する名前の特別な事前定義の定数を使用できます。SQL では、NaN(非数値)および無限大用の定数も定義されています。その他の整数は PL/SQL 専用です。

NUMBERNUMBERデータ型を使用すると、固定小数点数または浮動小数点数を格納できます。値の大きさの範囲は、1E-130 ~ 10E125 です。式の値がこの範囲外にあると、数値オーバーフローまたはアンダーフローのエラーが発生します。全体の桁数を精度(precision)として、小数点以下の桁数を位取り(scale)として指定できます。次に構文を示します。

NUMBER[(precision,scale)]

固定小数点数を宣言するには、位取り(scale)を指定する必要があります。次のフォームを使用します。

NUMBER(precision,scale)

浮動小数点数を宣言する場合は、小数点が任意の位置に浮動するため、精度(precision)や位取り(scale)を指定できません。次のフォームを使用します。

NUMBER

整数を宣言する場合は(小数点がありません)次のフォームを使用します。

NUMBER(precision) -- same as NUMBER(precision,0)

精度(precision)と位取り(scale)の指定には、定数や変数を使用できません。整数リテラルを使用する必要があります。NUMBER型の値の場合、精度(precision)の 大値は 10 進の 38 桁です。精度(precision)を指定しないと、38 か、デフォルトでシステムがサポートしている 大値のどちらか小さいほうになります。

位取り(scale)の範囲は -84 ~ 127 で、この値によって四捨五入の位置が決まります。たとえば、位取り(scale)として 2 を指定すると小数点以下 2 桁に四捨五入されます(3.456 は3.46 になります)。負の位取り(scale)を指定すると、小数点の左側で四捨五入されます。たとえば、位取り(scale)として -3 を指定すると、1000 の単位に四捨五入されます(3456は 3000 になります)。位取り(scale)として 0 を指定すると、 も近い整数値に四捨五入されます。位取り(scale)を指定しないと、デフォルトで 0(ゼロ)になります。

3-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 99: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

NUMBER サブタイプサブタイプサブタイプサブタイプ 次の NUMBERサブタイプは、名前の記述性を高め、ANSI/ISO およびIBM 型に対して互換性を保つ目的で用意されたデータ型です。

DECDECIMALDOUBLE PRECISIONFLOATINTEGERINTNUMERICREALSMALLINT

サブタイプ DEC、DECIMAL、NUMERICは、固定小数点数を宣言する場合に使用します。その場合、精度(precision)の 大値は 10 進数の 38 桁です。

サブタイプ DOUBLE PRECISIONと FLOATは、浮動小数点数を宣言する場合に使用します。その場合、精度(precision)の 大値は 2 進数の 126 桁であり、10 進数の 38 桁にほぼ等しくなります。サブタイプ REAL は、浮動小数点数を宣言する場合に使用します。その場合、精度(precision)の 大値は 2 進数で 63 桁であり、およそ 10 進数の 18 桁に等しくなります。

サブタイプ INTEGER、INT、SMALLINTは、整数を宣言する場合に使用します。その場合、精度(precision)の 大値は 10 進数の 38 桁です。

PLS_INTEGERPLS_INTEGERデータ型は、符号付き整数を格納するために使用します。値の大きさの範囲は、-2**31 ~ 2**31 です。PLS_INTEGER値は、NUMBERの値より小さい記憶域しか必要としません。また、PLS_INTEGER演算はマシン算術計算を使用するため、ライブラリ算術計算を使用する NUMBER演算や BINARY_INTEGER演算よりも処理速度が速くなります。効率のために、PLS_INTEGER の大きさの範囲内でのすべての計算に PLS_INTEGERを使用してください。

PLS_INTEGERと BINARY_INTEGERは、値の大きさの範囲は同じですが、完全に互換ではありません。PLS_INTEGER計算がオーバーフローすると、例外が発生します。ただし、BINARY_INTEGER計算がオーバーフローしても、結果が NUMBER変数に代入される場合には例外は発生しません。

このように、わずかですが意味上の違いがあるため、古いアプリケーションでは互換性を保てるように従来どおり BINARY_INTEGERを使用してください。新しいアプリケーションでは、より高いパフォーマンスを得るために必ず PLS_INTEGERを使用してください。

PL/SQL のデータ型 3-5

Page 100: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

PL/SQL の文字型と文字列型の文字型と文字列型の文字型と文字列型の文字型と文字列型キャラクタ・タイプは、英数字データの格納、ワードとテキストの表現および文字列の操作に使用します。

CHARCHARデータ型は固定長の文字データを格納するために使用します。データの内部表現形式は、データベース・キャラクタ・セットによって異なります。CHARデータ型はオプション・パラメータを使用して、その 大サイズを 32767 バイトまで指定できます。サイズはバイト数または文字数で指定できます。各文字には、キャラクタ・セットのエンコーディングに応じて 1 バイト以上が含まれます。次に構文を示します。

CHAR[(maximum_size [CHAR | BYTE] )]

大サイズには 1 ~ 32767 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。

大サイズを指定しなければ、デフォルトで 1 に設定されます。 大サイズを文字数ではなくバイト数で指定すると、CHAR(n)変数が小さすぎて n個のマルチバイト文字を保持できなくなる場合があります。この可能性を回避するには、データベース・キャラクタ・セットの一部の文字に複数のバイトが含まれていても、変数で n個の文字を保持できるように、表記法 CHAR(n CHAR)を使用します。文字数の長さを指定する場合の上限は、32767 バイトです。ダブルバイトおよびマルチバイトのキャラクタ・セットの場合、指定できるのは、シングルバイト・キャラクタ・セットの 1/2 または 1/3 の文字のみです。

PL/SQL の文字変数は比較的長くなりがちですが、2000 バイトを超える CHAR値は CHARデータベース列に挿入できません。

任意の CHAR(n)値を LONGデータベース列に格納できます。LONG列の 大幅は 2**31 バイト、つまり 2GB であるためです。ただし、LONG列から 32768 バイト以上の値を取り出してCHAR(n)に入れることはできません。

CHARまたは BYTE修飾子を使用しなければ、デフォルトは NLS_LENGTH_SEMANTICS初期化パラメータの設定によって決定されます。PL/SQL プロシージャのコンパイル時には、このパラメータの設定が記録されるため、プロシージャが無効になった後に再コンパイルするときにも同じ設定が使用されます。

注意注意注意注意 : CHARベース型と VARCHAR2ベース型の意味上の相違点については、付録 B を参照してください。

CHAR サブタイプサブタイプサブタイプサブタイプ CHARサブタイプ CHARACTERの値は、そのベース型と同じ範囲をとります。つまり、CHARACTERは CHARの別名にすぎません。このサブタイプは、CHAR型のみの場合よりも識別子の記述性を高め、ANSI/ISO および IBM 型に対して互換性を保つ目的で用意されたデータ型です。

3-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 101: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

LONG とととと LONG RAWLONGデータ型は、可変長の文字列を格納するために使用します。LONGデータ型は、LONG値の 大サイズが 32760 バイトであるという点を除けば、VARCHAR2データ型と同じです。

LONG RAWデータ型はバイナリ・データやバイト列を格納するために使用します。LONG RAWデータは、LONG RAW データが PL/SQL によって解釈されないという点を除けば、LONGデータと同じです。LONG RAW値の 大サイズは 32760 バイトです。

Oracle9i 以上では、LOB 変数を LONGおよび LONG RAW変数のかわりに使用できます。LONGデータを CLOB型に、LONG RAWデータを BLOB型に移行することをお薦めします。詳細は、3-13 ページの「PL/SQL LOB 型」を参照してください。

任意の LONG値を LONGデータベース列に格納できます。LONG列の 大幅は 2**31 バイトであるためです。ただし、LONG列から 32761 バイト以上の値を取り出して LONG変数に入れることはできません。

同様に、任意の LONG RAW値を LONG RAWデータベース列に格納できます。LONG RAW列の大幅は 2**31 バイトであるためです。ただし、LONG RAW列から 32761 バイト以上の値を

取り出して LONG RAW変数に入れることはできません。

LONG型の列にはテキスト、文字の配列、短いドキュメントなどを格納できます。LONG型の列は、UPDATE文、INSERT文および(ほとんどの)SELECT文で参照できますが、式やSQL 関数コール、または WHERE、GROUP BY、CONNECT BYといった一部の SQL 句では参照できません。詳細は、『Oracle Database SQL リファレンス』を参照してください。

注意注意注意注意 : SQL 文では、LONG値が LONGではなく VARCHAR2としてバインドされます。ただし、バインドされた VARCHAR2の長さが VARCHAR2列の 大幅(4000 バイト)を超える場合は、バインド型が LONGに自動的に変換され、エラー・メッセージが発行されます。これは、SQL ファンクションには LONG値を渡すことができないためです。

RAWRAWデータ型はバイナリ・データやバイト列を格納するために使用します。たとえば、RAW型変数には図形文字の並びやデジタル化された絵を格納できます。RAW データはVARCHAR2データと似ていますが、PL/SQL によって解釈されない点が異なります。また、RAW データをシステム間で送信する際に、Oracle Net はキャラクタ・セット変換を実行しません。

RAWデータ型は必須パラメータを使用して、その 大サイズを 32767 バイトまで指定できます。次に構文を示します。

RAW(maximum_size)

大サイズには 1 ~ 32767 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。

PL/SQL のデータ型 3-7

Page 102: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

長さ 2001 バイト以上の RAW値は RAW型の列に挿入できません。任意の RAW値を LONG RAWデータベース列に格納できます。LONG RAW列の 大幅は 2**31 バイトであるためです。ただし、LONG RAW列から 32768 バイト以上の値を取り出して RAW変数に入れることはできません。

ROWID とととと UROWID内部的に、すべてのデータベース表には、ROWID というバイナリ値を格納する ROWID疑似列があります。各 ROWID は、行の記憶域アドレスを表します。物理物理物理物理 ROWID は、通常の表の行を識別します。論理論理論理論理 ROWID は、索引構成表の行を識別します。ROWIDデータ型には物理 ROWID のみを格納できます。ただし、UROWID(ユニバーサル ROWID)データ型には物理 ROWID、論理 ROWID、外部(非 Oracle)ROWID を格納できます。

提案提案提案提案 : ROWIDデータ型は、古いアプリケーションとの下位互換性のためのみに使用してください。新しいアプリケーションの場合には、UROWIDデータ型を使用します。

ROWID を選択またはフェッチして ROWID変数に入れる場合は、バイナリ値を 18 バイトの文字列に変換する組込みファンクション ROWIDTOCHARを使用します。逆に、ファンクション CHARTOROWIDは ROWID文字列を ROWID に変換します。文字列が有効な ROWID を表していないために変換が失敗すると、PL/SQL は事前定義の例外 SYS_INVALID_ROWIDを発生します。これは、暗黙的な変換にも適用されます。

UROWID変数と文字列間で変換するには、ファンクション・コールなしで通常の代入文を使用します。値は、UROWIDとキャラクタ・タイプの間で暗黙的に変換されます。

物理物理物理物理 ROWID 物理 ROWID を使用すると、特定の行にすばやくアクセスできます。物理ROWID は、その行が存在するかぎり変わりません。ROWID は効率的で安定しているため、行の集合を選択し、集合全体を操作してサブセットを更新するのに便利です。たとえば、UPDATE文または DELETE文の WHERE句の中で UROWID変数と ROWID疑似列を比較して、カーソルからフェッチされた 新の行を識別できます。6-44 ページの「コミットにまたがるフェッチ」を参照してください。

物理 ROWID には 2 つの形式があります。10 バイトの拡張 ROWID 形式は相対表領域ブロック・アドレスをサポートしており、パーティション化表と非パーティション化表の行を識別できます。6 バイトの制限 ROWID 形式は、下位互換性のために用意されています。

拡張 ROWID は、選択された各行の物理アドレスの base-64 エンコーディングを使用します。たとえば、ROWID を暗黙的に文字列に変換する SQL*Plus での次の問合せを考えてみます。

SQL> SELECT rowid, ename FROM emp WHERE empno = 7788;

これは、次の行を戻します。

ROWID ENAME------------------ ----------AAAAqcAABAAADFNAAH SCOTT

3-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 103: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

形式 OOOOOOFFFBBBBBBRRRは、4 つの部分に分かれています。

� OOOOOO: データ・オブジェクト番号(上の例では AAAAqc)。データベース・セグメントを識別します。表のクラスタなど、同じセグメント中のスキーマ・オブジェクトのデータ・オブジェクト番号は同じです。

� FFF: ファイル番号(上の例では AAB)。行が入っているデータ・ファイルを識別します。ファイル番号はデータベース内で一意です。

� BBBBBB: ブロック番号(上の例では AAADFN)。行が入っているデータ・ブロックを識別します。ブロック番号は、その表領域ではなく、データ・ファイルに対応します。このため、同じ表領域内の異なるデータ・ファイルにある 2 つの行は、同じブロック番号を持つことができます。

� RRR: 行番号(上の例では AAH)。ブロック内の行を識別します。

論理論理論理論理 ROWID 論理 ROWID を使用すると、特定の行に も早くアクセスできます。Oracle は論理 ROWID を使用して索引構成表の 2 次索引を組み立てます。論理 ROWID は恒久物理アドレスを持たないため、新しい行が挿入されると複数のデータ・ブロックの間を移動できます。ただし、行の物理的な位置が変わった場合、その論理 ROWID は有効なまま残ります。

論理 ROWID には不確定要素を含めることができます。これは推測が行われたときの行のブロック位置を識別します。Oracle は全体のキー検索をせずに、不確定要素を使用してブロックを直接検索します。ただし新しい行が挿入されると、不確定要素は古くなって行へのアクセスの処理速度が遅くなります。新しい不確定要素を得るには、2 次索引を再作成します。

ROWID疑似列を使用して、索引構成表から論理 ROWID(これは不透明値です)を選択できます。また、 大サイズが 4000 バイトの UROWID型の列に論理 ROWID を挿入できます。

ANALYZE文は、推測の古さを追跡するために役立ちます。これは、推測を持つ ROWID をUROWID列に格納し、その ROWID を使用して行をフェッチするアプリケーションの場合に便利です。

注意注意注意注意 : ROWID を操作するには、提供されているパッケージ DBMS_ROWIDを使用します。詳細は、『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

VARCHAR2VARCHAR2データ型は可変長の文字データを格納するために使用します。データの内部表現形式は、データベース・キャラクタ・セットによって異なります。VARCHAR2データ型は必須パラメータを使用して、その 大サイズを 32767 バイトまで指定できます。次に構文を示します。

VARCHAR2(maximum_size [CHAR | BYTE])

大サイズには 1 ~ 32767 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。

PL/SQL のデータ型 3-9

Page 104: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

VARCHAR2変数が小さい場合はパフォーマンスに合わせて 適化され、大きい場合は効率的なメモリー使用に合わせて 適化されます。分離点は 2000 バイトです。長さ 2000バイト以上の VARCHAR2の場合、PL/SQL は実際の値を保持するために必要なだけのメモリーを動的に割り当てます。長さ 2000 バイト未満の VARCHAR2変数の場合は、変数の宣言済の長さ全体が事前に割り当てられます。たとえば VARCHAR2(2000 BYTE)変数とVARCHAR2(1999 BYTE)変数に同じ 500 バイトの値を割り当てると、前者の変数は 500 バイト、後者は 1999 バイトのメモリーを使用することになります。

大サイズを文字数ではなくバイト数で指定すると、VARCHAR2(n)変数が小さすぎて n個のマルチバイト文字を保持できないことがあります。この可能性を回避するには、データベース・キャラクタ・セットの一部の文字に複数のバイトが含まれていても、変数で n個の文字を保持できるように、表記法 VARCHAR2(n CHAR)を使用します。文字数の長さを指定する場合の上限は、32767 バイトです。ダブルバイトおよびマルチバイトのキャラクタ・セットの場合、指定できるのは、シングルバイト・キャラクタ・セットの 1/2 または 1/3 の文字のみです。

PL/SQL の文字変数は比較的長くなりがちですが、4000 バイトを超える VARCHAR2値はVARCHAR2データベース列に挿入できません。

任意の VARCHAR2(n)値を LONGデータベース列に格納できます。LONG列の 大幅は 2**31バイトであるためです。ただし、LONG列から 32768 バイト以上の値を取り出してVARCHAR2(n)に入れることはできません。

CHARまたは BYTE修飾子を使用しなければ、デフォルトは NLS_LENGTH_SEMANTICS初期化パラメータの設定によって決定されます。PL/SQL プロシージャのコンパイル時には、このパラメータの設定が記録されるため、プロシージャが無効になった後に再コンパイルするときにも同じ設定が使用されます。

VARCHAR2 サブタイプサブタイプサブタイプサブタイプ 次の VARCHAR2サブタイプの値は、そのベース型と同じ範囲をとります。たとえば、VARCHARは VARCHAR2の別名です。

STRINGVARCHAR

このサブタイプは、ANSI/ISO 型と IBM 型に対する互換性を保つ目的で用意されたデータ型です。

注意注意注意注意 : 現在のところ、VARCHARは VARCHAR2と同義です。ただし、PL/SQL の今後のリリースでの VARCHARは、SQL 標準に従うために比較時の意味が異なる別個のデータ型になる可能性があります。VARCHARではなく VARCHAR2を使用することをお薦めします。

3-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 105: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

PL/SQL の各国語キャラクタ・タイプの各国語キャラクタ・タイプの各国語キャラクタ・タイプの各国語キャラクタ・タイプよく使用される 1 バイトの ASCII と EBCDIC のキャラクタ・セットはアルファベットを表示するには十分ですが、日本語などのアジアの言語には何千もの文字があります。これらの言語では、1 文字を表すために 2 バイトまたは 3 バイトが必要です。Oracle にはグローバリゼーション・サポートが用意されており、シングルバイト文字データとマルチバイト文字データを処理したり、キャラクタ・セット間で変換することができます。また、アプリケーションを複数の異なる言語環境で実行できます。

グローバリゼーション・サポートによって、数字と日付の形式は、ユーザー・セッションで指定されている言語の規則に自動的に合わせられます。したがって、世界中のユーザーはOracle を使用して母国語で対話できます。

PL/SQL は、識別子およびソース・コードに使用されるデータベース・キャラクタ・セットと、各国語データに使用される各国語キャラクタ・セットの 2 つのキャラクタ・セットをサポートしています。データ型 NCHARと NVARCHAR2は、各国語キャラクタ・セットから構成される文字列を格納できます。

注意注意注意注意 : CHARデータまたは VARCHAR2データをキャラクタ・セットが異なるデータベース間で変換する場合は、データが適切な形式の文字列で構成されていることを確認してください。詳細は、『Oracle Database グローバリゼーション・サポート・ガイド』を参照してください。

UTF8 およびおよびおよびおよび AL16UTF16 エンコーディングエンコーディングエンコーディングエンコーディング各国語キャラクタ・セットでは、データは UTF8または AL16UTF16エンコーディングを使用して Unicode として表されます。

AL16UTF16エンコーディングの場合、各文字は 2 バイトです。このため、異なるプログラミング言語が混在する場合に、文字列長を計算して切捨てエラーを回避するのは簡単ですが、ほとんどが ASCII 文字で構成される文字列を格納するために余分なストレージ・オーバーヘッドを必要とします。

UTF8エンコーディングの場合、各文字は 1、2 または 3 バイトです。このため、ほとんどの文字を 1 バイトで表せる場合にのみ、変数や表の列に、より多数の文字を入れることができます。データをバイト単位のバッファに転送すると、切捨てエラーになる可能性があります。

実行時に 大限の信頼性が得られるように、できるかぎりデフォルトの AL16UTF16エンコーディングを使用することをお薦めします。Unicode 文字列の保持に必要なバイト数を判断する場合は、LENGTHではなく LENGTHBファンクションを使用してください。

PL/SQL のデータ型 3-11

Page 106: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

NCHARNCHARデータ型は、固定長の(必要に応じて空白埋めされる)各国語キャラクタ・データを格納するために使用します。データの内部表現形式は、データベースの作成時に指定した各国語キャラクタ・セット、つまり、可変幅のエンコーディング(UTF8)を使用するか、それとも固定幅のエンコーディング(AL16UTF16)を使用するかによって異なります。この型は常にマルチバイト文字に対処できるため、Unicode データの保持に使用できます。

NCHARデータ型はオプション・パラメータを使用して、その 大サイズを文字数で指定できます。次に構文を示します。

NCHAR[(maximum_size)]

物理的な上限は 32767 バイトのため、長さに指定できる 大値は、AL16UTF16エンコーディングの場合は 32767/2、UTF8エンコーティングの場合は 32767/3 です。

大サイズには整数リテラルを指定します。シンボリック定数や変数は指定できません。

大サイズを指定しなければ、デフォルトの 1 が使用されます。CHARでは文字数またはバイト数で指定できますが、この値は常に文字数を表します。

my_string NCHAR(100); -- maximum size is 100 characters

長さ 2001 バイト以上の NCHAR値は NCHAR型の列に挿入できません。

NCHAR値が NCHAR列の定義された幅より短ければ、Oracle は定義幅まで値を空白で埋めます。

CHARおよび NCHAR値は、文と式の中で交換できます。常に安全に CHAR値が NCHAR値になりますが、CHAR値のキャラクタ・セットで NCHAR値のすべての文字を表すことができない場合は、NCHAR値を CHAR値にするとデータが失われる場合があります。このようなデータの消失が発生すると、各文字では通常は疑問符(?)のようになります。

NVARCHAR2NVARCHAR2データ型は、可変長の Unicode 文字データの格納に使用します。データの内部表現形式は、データベースの作成時に指定した各国語キャラクタ・セット、つまり、可変幅のエンコーディング(UTF8)を使用するか、それとも固定幅のエンコーディング

(AL16UTF16)を使用するかによって異なります。この型は常にマルチバイト文字に対処できるため、Unicode データの保持に使用できます。

NVARCHAR2データ型は必須パラメータを使用して、その 大サイズを文字数で指定できます。次に構文を示します。

NVARCHAR2(maximum_size)

物理的な上限は 32767 バイトのため、長さに指定できる 大値は、AL16UTF16エンコーディングの場合は 32767/2、UTF8エンコーティングの場合は 32767/3 です。

大サイズには整数リテラルを指定します。シンボリック定数や変数は指定できません。

3-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 107: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

大サイズを文字数またはバイト数で指定できる VARCHAR2とは異なり、 大サイズは常に文字数を表します。

my_string NVARCHAR2(200); -- maximum size is 200 characters

NVARCHAR2データベース列の 大幅は 4000 バイトです。このため、4000 バイトよりも長い NVARCHAR2値を NVARCHAR2型の列に挿入できません。

VARCHAR2および NVARCHAR2値は、文と式の中で交換できます。VARCHAR2値をNVARCHAR2値にするのは常に問題ありませんが、NVARCHAR2値のすべての文字がVARCHAR2値のキャラクタ・セットで表せるとはかぎらない場合は、NVARCHAR2値をVARCHAR2値にするとデータが失われる場合があります。このようなデータの消失が発生すると、各文字では通常は疑問符(?)のようになります。

PL/SQL LOB 型型型型LOB(ラージ・オブジェクト)データ型 BFILE、BLOB、CLOBおよび NCLOBは、構造化されていないデータ(テキスト、図形イメージ、ビデオ・クリップ、サウンド・ウェーブ形式など)のブロックを、4GB まで格納するために使用します。さらに、効率的、かつランダムで、断片的なデータへのアクセスができます。

LOB型は、いくつかの点で LONG型と LONG RAW型とは異なります。たとえば、LOB(NCLOBを除く)はオブジェクト型の属性として使用できますが、LONGは使用できません。LOBの 大サイズは 4GB ですが、LONGの 大サイズは 2GB です。また、LOBではデータのランダム・アクセスがサポートされていますが、LONGでは順次アクセスしかサポートされていません。

LOB型には LOB ロケータが格納されます。これは、外部ファイル、インライン(行内部)、またはライン外(行外部)に格納される大きなオブジェクトの位置を指定するものです。BLOB型、CLOB型、NCLOB型または BFILE型のデータベース列にはロケータが格納されます。BLOBデータ、CLOBデータおよび NCLOBデータは、データベース内の行内部または行外部に格納されます。BFILEデータは、データベース外のオペレーティング・システム・ファイルに格納されます。

PL/SQL の LOBは、ロケータによって操作されます。たとえば、BLOB列の値を選択した場合、ロケータのみが戻されます。トランザクション中に取得した場合、LOBロケータにはトランザクション ID が含まれるため、別のトランザクションの LOBの更新にはその LOB ロケータを使用できません。同様にあるセッション中に LOBロケータを保管してから、それを別のセッションで使用することはできません。

Oracle9i 以上では、CLOBと CHARおよび VARCHAR2型との間の変換や、BLOBと RAWとの間の変換も可能です。このため、LOB型はほとんどの SQL および PL/SQL の文とファンクションに使用できます。LOBの読取り、書込みおよびピース単位の操作を行うには、オラクル社が提供するパッケージ DBMS_LOBを使用できます。詳細は、『Oracle Database アプリケーション開発者ガイド - ラージ・オブジェクト』を参照してください。

PL/SQL のデータ型 3-13

Page 108: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

BFILEBFILEデータ型は、データベース外のオペレーティング・システム・ファイルに大規模なバイナリ・オブジェクトを格納するために使用します。どの BFILE変数にも、サーバー上の大規模なバイナリ・ファイルを指すファイル・ロケータが格納されています。ロケータには、フル・パス名を指定するディレクトリ別名が含まれています(論理パス名はサポートされていません)。

BFILEは読取り専用です。変更はできません。BFILEのサイズはシステムに依存していますが、4GB(2**32 - 1 バイト)を超えるものは使用できません。指定された BFILEが存在し、Oracle にその読取り許可があることは、DBA によって保証されます。基礎となるオペレーティング・システムがファイルの整合性を維持します。

BFILEはトランザクションには関与せず、リカバリ可能ではなく、レプリケートできません。オープンする BFILEの 大数は、システムに依存する Oracle 初期化パラメータSESSION_MAX_OPEN_FILESによって設定されます。

BLOBBLOBデータ型は、データベース内の行内部または行外部に大規模なバイナリ・オブジェクトを格納するために使用します。どの BLOB変数にも、大規模なバイナリ・オブジェクトを指すロケータが格納されます。BLOBのサイズは 4GB 以下にしてください。

BLOBはトランザクションに完全に関与し、リカバリ可能で、レプリケートできます。パッケージ DBMS_LOBによって行われた変更は、コミットまたはロールバックできます。BLOBロケータは複数の(読取り専用)トランザクションにまたがることはできますが、複数のセッションにはまたがることができません。

CLOBCLOBデータ型は、文字データの大規模なブロックを、データベース内の行内部または行外部に格納するために使用します。固定幅と可変幅の、両方のキャラクタ・セットがサポートされています。どの CLOB変数にも、文字データの大規模なブロックを指すロケータが格納されます。CLOBのサイズは 4GB 以下にしてください。

CLOBはトランザクションに完全に関与し、リカバリ可能で、レプリケートできます。パッケージ DBMS_LOBによって行われた変更は、コミットまたはロールバックできます。CLOBロケータは複数の(読取り専用)トランザクションにまたがることはできますが、複数のセッションにはまたがることができません。

NCLOBNCLOBデータ型は、NCHARデータの大規模なブロックを、データベース内の行内部または行外部に格納するために使用します。固定幅と可変幅の、両方のキャラクタ・セットがサポートされています。どの NCLOB変数にも、NCHARデータの大規模なブロックを指すロケータが格納されます。NCLOBのサイズは 4GB 以下にしてください。

3-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 109: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

NCLOBはトランザクションに完全に関与し、リカバリ可能で、レプリケートできます。パッケージ DBMS_LOBによって行われた変更は、コミットまたはロールバックできます。NCLOBロケータは複数の(読取り専用)トランザクションにまたがることはできますが、複数のセッションにはまたがることができません。

PL/SQL のブール型のブール型のブール型のブール型PL/SQL には、ブール値(TRUE と FALSE)を表現するための型があります。SQL には同等の型がないため、BOOLEAN変数とパラメータは、PL/SQL コンテキスト内では使用できますが、SQL 文または SQL 問合せでは使用できません。

BOOLEANBOOLEANデータ型は、論理値 TRUEと FALSE、および NULL(存在しない値、未知の値または適用不可能な値を表す)を格納するために使用します。BOOLEAN変数で可能な操作は論理操作のみです。

BOOLEANデータ型はパラメータを取りません。BOOLEAN変数に代入できるのは、値 TRUE、FALSEおよび NULLのみです。

データベース列には値 TRUEや FALSEを挿入できません。列の値を選択またはフェッチして BOOLEAN変数に入れることはできません。SQL 問合せからのファンクション・コールに、BOOLEANパラメータは使用できません。TO_CHARなどの組込み SQL ファンクションでも BOOLEAN値を出力できないため、IF-THEN文または CASE文を使用して、BOOLEAN値を 0 か 1、Y か N、TRUE か FALSE などの別の型に変換する必要があります。

PL/SQL の日付型、時刻型および時間隔型の日付型、時刻型および時間隔型の日付型、時刻型および時間隔型の日付型、時刻型および時間隔型この項で説明するデータ型を使用すると、日付、時刻および時間隔(期間)を格納し、操作できます。日付 / 時刻型の変数には日時と呼ばれる値が保持され、時間隔型の変数には時間隔と呼ばれる値が保持されます。日時または時間隔は、その値を決定するフィールドで構成されます。次のリストに、各フィールドの有効値を示します。

フィールド名フィールド名フィールド名フィールド名 有効な日時値有効な日時値有効な日時値有効な日時値 有効な時間隔値有効な時間隔値有効な時間隔値有効な時間隔値

YEAR -4712 ~ 9999(年 0 を除く) 0 以外の任意の整数

MONTH 01 ~ 12 0 ~ 11

DAY 01 ~ 31(ロケールのカレンダの規則に

従って MONTHおよび YEARの値による

制限付き)

0 以外の任意の整数

HOUR 00 ~ 23 0 ~ 23

MINUTE 00 ~ 59 0 ~ 59

PL/SQL のデータ型 3-15

Page 110: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

TIMESTAMP WITH LOCAL TIMEZONEを除き、前述の型はすべて SQL92 規格の一部です。日時および時間隔のフォーマット・モデル、リテラル、タイムゾーン名および SQL ファンクションの詳細は、『Oracle Database SQL リファレンス』を参照してください。

DATEDATEデータ型は、午前 0 時からの経過秒数を含む固定長の日時の格納に使用します。デフォルトでは、日付部分は現在の月の 初の日であり、時刻の部分は午前 0 時です。日付関数 SYSDATEは、現在の日付と時刻を戻します。

ヒントヒントヒントヒント :

� 日付の等価性を各日付の時刻の部分に関係なく比較するには、比較、GROUP BY操作などにファンクションの結果 TRUNC(date_variable)を使用します。

� DATE 変数の時刻の部分のみを確認するには、日付の部分を引きます(date_variable - TRUNC(date_variable))。

使用できる日付は、紀元前 4712 年 1 月 1 日から西暦 9999 年 12 月 31 日までです。ユリウス日付は、紀元前 4712 年 1 月 1 日からの日数です。ユリウス日付によって、共通の参照元からの連続した日付が可能になります。日付関数 TO_DATEと TO_CHARで日付書式モデル'J'を使用すると、DATE値とそれに対応するユリウス日付の値の間で変換できます。

日付式の中では、デフォルトの日付書式の文字値は自動的に DATE値に変換されます。デフォルトの日付書式は、Oracle 初期化パラメータ NLS_DATE_FORMATによって設定されます。たとえば、デフォルトは 'DD-MON-YY'であり、これは 2 桁数字の日、月の省略名、年数の下 2 桁を含むものということです。

日付に対しては加算および減算ができます。算術式の中では、PL/SQL は整数リテラルを日数として解釈します。たとえば、SYSDATE + 1 は、次の日の同じ時刻ということです。

SECOND 00 ~ 59.9(n)、9(n) は時刻の秒の精度 0 ~ 59.9(n)、9(n) は時間隔の秒

の精度

TIMEZONE_HOUR -12 ~ 14(範囲は夏時間の変更に対応) 該当なし

TIMEZONE_MINUTE 00 ~ 59 該当なし

TIMEZONE_REGION ビュー V$TIMEZONE_NAMESに表示 該当なし

TIMEZONE_ABBR ビュー V$TIMEZONE_NAMESに表示 該当なし

フィールド名フィールド名フィールド名フィールド名 有効な日時値有効な日時値有効な日時値有効な日時値 有効な時間隔値有効な時間隔値有効な時間隔値有効な時間隔値

3-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 111: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

TIMESTAMPTIMESTAMPデータ型は DATEデータ型への拡張であり、年、月、日、時間、分および秒が格納されます。次に構文を示します。

TIMESTAMP[(precision)]

オプションの precisionパラメータでは、秒のフィールドの小数部の桁数を指定します。精度には 0 ~ 9 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。デフォルトは 6 です。

デフォルトのタイムスタンプ日付書式は、Oracle 初期化パラメータNLS_TIMESTAMP_FORMATによって設定されます。

次の例では、TIMESTAMP型の変数を宣言してからリテラル値を代入しています。

DECLARE checkout TIMESTAMP(3);BEGIN checkout := '1999-06-22 07:48:53.275'; ...END;

この例では、秒フィールドの小数部は 0.275です。

TIMESTAMP WITH TIME ZONETIMESTAMP WITH TIME ZONEデータ型は、TIMESTAMPデータ型への拡張であり、タイムタイムタイムタイムゾーンによる時差ゾーンによる時差ゾーンによる時差ゾーンによる時差を含みます。タイムゾーンによる時差とは、現地時間と協定世界時

(UTC、旧称はグリニッジ標準時)の時差(時間および分単位)です。次に構文を示します。

TIMESTAMP[(precision)] WITH TIME ZONE

オプションの precisionパラメータでは、秒のフィールドの小数部の桁数を指定します。精度には 0 ~ 9 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。デフォルトは 6 です。

デフォルトのタイムゾーン付きタイムスタンプの書式は、Oracle 初期化パラメータNLS_TIMESTAMP_TZ_FORMATによって設定されます。

次の例では、TIMESTAMP WITH TIME ZONE型の変数を宣言してからリテラル値を代入しています。

DECLARE logoff TIMESTAMP(3) WITH TIME ZONE;BEGIN logoff := '1999-10-31 09:42:37.114 +02:00'; ...END;

PL/SQL のデータ型 3-17

Page 112: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

この例では、タイムゾーンによる時差は +02:00です。

また、シンボリック名でタイムゾーンを指定することもできます。この指定には、'US/Pacific'などの長い形式、'PDT'などの省略形またはその組合せを使用できます。たとえば、次のリテラルはいずれも同じ時刻を表します。3 番目は、夏時間に切り替わった時点で適用される規則を指定しているため、 も信頼性の高い書式です。

TIMESTAMP '1999-04-15 8:00:00 -8:00'TIMESTAMP '1999-04-15 8:00:00 US/Pacific'TIMESTAMP '1999-10-31 01:30:00 US/Pacific PDT'

タイムゾーンに使用可能な名前は、V$TIMEZONE_NAMESデータ・ディクショナリ・ビューの TIMEZONE_REGIONおよび TIMEZONE_ABBR列にあります。

2 つの TIMESTAMP WITH TIME ZONE値は、UTC で同じ時間を表していれば、タイムゾーンによる時差に関係なく同一とみなされます。たとえば、UTC の太平洋標準時で午前 8:00 は東部標準時の午前 11:00 と同じであるため、次の 2 つの値は同一とみなされます。

'1999-08-29 08:00:00 -8:00''1999-08-29 11:00:00 -5:00'

TIMESTAMP WITH LOCAL TIME ZONETIMESTAMP WITH LOCAL TIME ZONEデータ型は、TIMESTAMPデータ型への拡張であり、タイムゾーンによる時差タイムゾーンによる時差タイムゾーンによる時差タイムゾーンによる時差を含みます。タイムゾーンによる時差とは、現地時間と協定世界時

(UTC、旧称はグリニッジ標準時)の時差(時間および分単位)です。TIMESTAMP WITH TIME ZONEと同様に、名前付きのタイム・ゾーンも使用できます。

次に構文を示します。

TIMESTAMP[(precision)] WITH LOCAL TIME ZONE

オプションの precisionパラメータでは、秒のフィールドの小数部の桁数を指定します。精度には 0 ~ 9 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。デフォルトは 6 です。

このデータ型は、TIMESTAMP WITH TIME ZONEとは異なり、データベース列に値を挿入すると、値はデータベースのタイム・ゾーンに正規化され、タイムゾーンによる時差は列に格納されません。値を取り出すときには、ローカル・セッションのタイム・ゾーンで戻されます。

次の例では、TIMESTAMP WITH LOCAL TIME ZONE型の変数を宣言しています。

DECLARE logoff TIMESTAMP(3) WITH LOCAL TIME ZONE;BEGIN ...END;

この型の変数には、リテラル値を代入できません。

3-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 113: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

INTERVAL YEAR TO MONTHINTERVAL YEAR TO MONTHデータ型は、年および月の時間隔を格納し、操作するために使用します。次に構文を示します。

INTERVAL YEAR[(precision)] TO MONTH

precisionでは、年フィールドの桁数を指定します。精度には 0 ~ 4 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。デフォルトは 2 です。

次の例では、INTERVAL YEAR TO MONTH型の変数を宣言してから、101 年および 3 月の値を代入しています。

DECLARE lifetime INTERVAL YEAR(3) TO MONTH;BEGIN lifetime := INTERVAL '101-3' YEAR TO MONTH; -- interval literal lifetime := '101-3'; -- implicit conversion from character type lifetime := INTERVAL '101' YEAR; -- Can specify just the years lifetime := INTERVAL '3' MONTH; -- Can specify just the months ...END;

INTERVAL DAY TO SECONDINTERVAL DAY TO SECONDデータ型は、日、時間、分および秒の時間隔を格納し、操作するために使用します。次に構文を示します。

INTERVAL DAY[(leading_precision)] TO SECOND[(fractional_seconds_precision)]

leading_precisionおよび fractional_seconds_precisionでは、それぞれ日付フィールドと秒フィールドの桁数を指定します。どちらの場合も、精度には 0 ~ 9 の範囲の整数リテラルを指定します。シンボリック定数や変数は指定できません。デフォルトはそれぞれ 2 および 6 です。

次の例では、INTERVAL DAY TO SECOND型の変数を宣言しています。

DECLARE lag_time INTERVAL DAY(3) TO SECOND(3);BEGIN IF lag_time > INTERVAL '6' DAY THEN ... ...END;

PL/SQL のデータ型 3-19

Page 114: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義された PL/SQL データ型の概要

日時および時間隔の演算日時および時間隔の演算日時および時間隔の演算日時および時間隔の演算PL/SQL では、日時式と時間隔式を作成できます。この種の式に使用できる演算子を次のリストに示します。

また、EXTRACTなどの各種ファンクションを使用して日時値を操作することもできます。この種のファンクションのリストは、2-39 ページの表 2-3「組込みファンクション」を参照してください。

日時の演算の詳細は、『Oracle Database SQL リファレンス』および『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

日付および時刻のサブタイプを使用する場合の切捨て問題の回避日付および時刻のサブタイプを使用する場合の切捨て問題の回避日付および時刻のサブタイプを使用する場合の切捨て問題の回避日付および時刻のサブタイプを使用する場合の切捨て問題の回避日時の型のデフォルト精度は、 大精度より低い場合があります。たとえば、DAY TO SECONDのデフォルトは DAY(2) TO SECOND(6)ですが、 大精度は DAY(9) TO SECOND(9)です。この種の型の変数を代入し、プロシージャのパラメータを渡す場合に切り捨てを防ぐためには、次のサブタイプの変数とプロシージャのパラメータを宣言できます。各サブタイプでは、精度に 大値が使用されます。

TIMESTAMP_UNCONSTRAINEDTIMESTAMP_TZ_UNCONSTRAINEDTIMESTAMP_LTZ_UNCONSTRAINEDYMINTERVAL_UNCONSTRAINEDDSINTERVAL_UNCONSTRAINED

オペランドオペランドオペランドオペランド 1 演算子演算子演算子演算子 オペランドオペランドオペランドオペランド 2 結果タイプ結果タイプ結果タイプ結果タイプ

日時 + 時間隔 日時

日時 - 時間隔 日時

時間隔 + 日時 日時

日時 - 日時 時間隔

時間隔 + 時間隔 時間隔

時間隔 - 時間隔 時間隔

時間隔 * 数値 時間隔

数値 * 時間隔 時間隔

時間隔 / 数値 時間隔

3-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 115: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブタイプの概要

PL/SQL サブタイプの概要サブタイプの概要サブタイプの概要サブタイプの概要PL/SQL のベース型はそれぞれ、その型の項目に適用可能な値のセットや演算のセットを指定します。サブタイプは、そのベース型と同じ演算のセットを指定しますが、指定する値はベース型のサブセットのみです。サブタイプは新しい型を導入するためのものではありません。単にそのベース型に対してオプションの制約を定義するためのものです。

サブタイプを使用すると、信頼性が向上し、ANSI/ISO 型との互換性が保たれ、さらに定数や変数の使用意図を示すことで読みやすさが向上します。PL/SQL では、パッケージSTANDARDの中にいくつかのサブタイプが事前に定義されています。たとえば、PL/SQL では、サブタイプ CHARACTERおよび INTEGERが次のようにあらかじめ定義されています。

SUBTYPE CHARACTER IS CHAR;SUBTYPE INTEGER IS NUMBER(38,0); -- allows only whole numbers

サブタイプ CHARACTERは、そのベース型 CHARと同じ値の集合を指定します。したがって、CHARACTERは無制約サブタイプです。ただし、サブタイプ INTEGERは、そのベース・タイプ NUMBERの値のサブセットのみを指定するため、INTEGERは制約付きサブタイプです。

サブタイプの定義サブタイプの定義サブタイプの定義サブタイプの定義ユーザー独自のサブタイプは、次の構文を使用して、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で定義できます。

SUBTYPE subtype_name IS base_type[(constraint)] [NOT NULL];

ここで subtype_nameは後続の宣言で使用される型指定子です。base_typeは任意のスカラーまたはユーザー定義の PL/SQL データ型で、constraintは精度およびスケールまたは 大サイズを指定できるベース型にのみ適用されます。

次に例を示します。

DECLARE SUBTYPE BirthDate IS DATE NOT NULL; -- based on DATE type SUBTYPE Counter IS NATURAL; -- based on NATURAL subtype TYPE NameList IS TABLE OF VARCHAR2(10); SUBTYPE DutyRoster IS NameList; -- based on TABLE type TYPE TimeRec IS RECORD (minutes INTEGER, hours INTEGER); SUBTYPE FinishTime IS TimeRec; -- based on RECORD type SUBTYPE ID_Num IS emp.empno%TYPE; -- based on column type

%TYPEまたは %ROWTYPEを使用してベース型を指定できます。%TYPEがデータベース列のデータ型を提供する場合、サブタイプはその列のサイズ制約(存在する場合)を継承します。NOT NULLのような他の種類の制約は継承しません。

PL/SQL のデータ型 3-21

Page 116: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブタイプの概要

サブタイプの使用サブタイプの使用サブタイプの使用サブタイプの使用一度サブタイプを定義すると、その型の項目を宣言できます。次の例では、Counter型の変数を宣言しています。変数の使用意図がサブタイプ名によってどのように示されているかに注意してください。

DECLARE SUBTYPE Counter IS NATURAL; rows Counter;

ユーザー定義のサブタイプに属する変数を宣言する場合に、そのサブタイプについて制約を設定できます。

DECLARE SUBTYPE Accumulator IS NUMBER; total Accumulator(7,2);

サブタイプを使用すると、範囲外の値を検出でき、信頼性が向上します。次の例では、-9 ~ 9 の範囲の整数を格納するようにサブタイプ Numeralを制限しています。プログラムで Numeral変数の範囲外の数値を格納すると、PL/SQL は例外を呼び出します。

DECLARE SUBTYPE Numeral IS NUMBER(1,0); x_axis Numeral; -- magnitude range is -9 .. 9 y_axis Numeral;BEGIN x_axis := 10; -- raises VALUE_ERROR ...END;

データ型の互換性データ型の互換性データ型の互換性データ型の互換性無制約のサブタイプは、そのベース型と互換性があります。たとえば、次のように宣言すると、amountの値を変換せずに totalに代入できます。

DECLARE SUBTYPE Accumulator IS NUMBER; amount NUMBER(7,2); total Accumulator;BEGIN ... total := amount; ...END;

異なるサブタイプでも、ベース型が同じならば互換性があります。

DECLARE SUBTYPE b1 IS BOOLEAN; SUBTYPE b2 IS BOOLEAN;

3-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 117: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL データ型の変換

finished b1; -- Different subtypes, debugging b2; -- both based on BOOLEAN.BEGIN debugging := finished; -- They can be assigned to each other.END;

また、異なるサブタイプの場合、ベース型が同じデータ型の系列ならば互換性があります。たとえば、次のように宣言すると、verbの値を sentenceに代入できます。

DECLARE SUBTYPE Word IS CHAR(15); SUBTYPE Text IS VARCHAR2(1500); verb Word; -- Different subtypes sentence Text(150); -- of types from the same familyBEGIN sentence := verb; -- can be assigned, if not too long.END;

PL/SQL データ型の変換データ型の変換データ型の変換データ型の変換あるデータ型の値を別のデータ型に変換することが必要な場合があります。たとえば DATE変数をレポートで使用するには、これを文字列に変換する必要があります。データ型の変換について PL/SQL では、明示的な変換と暗黙的(自動的)な変換がサポートされています。意図したとおりにプログラムを動作させるには、できるかぎり明示的な変換を行います。

明示的な変換明示的な変換明示的な変換明示的な変換値のデータ型を別のデータ型に変換するには、組込みファンクションを使用します。たとえば、CHAR値を DATE値または NUMBER値に変換するには、それぞれ TO_DATEファンクションまたは TO_NUMBERファンクションを使用します。逆に、DATE値または NUMBER値をCHAR値に変換するには、TO_CHARファンクションを使用します。これらのファンクションの詳細は、『Oracle Database SQL リファレンス』を参照してください。

明示的な変換を行うと、特にサブプログラムにパラメータを渡す際に、予測しないエラーや誤った結果の発生を回避することができます。たとえば、TO_CHARファンクションを使用すると、データベースの言語設定にかかわらず、DATE値の形式を指定できます。||演算子で連結した文字列に算術式を含める場合、算術式をカッコで囲むか、または算術式の周りにTO_CHARへのコールを挿入しないかぎり、エラーが発生する可能性があります。

暗黙的な変換暗黙的な変換暗黙的な変換暗黙的な変換変換して意味がある場合、PL/SQL は暗黙的にデータ型の変換を実行することがあります。この機能によって、ある型のリテラル、変数またはパラメータを、別の型が期待されている箇所で使用できます。たとえば、通常は文字列を受け取るサブプログラムに数値リテラルを渡すことができます。サブプログラムは、数値の文字列表現を受け取ります。

PL/SQL のデータ型 3-23

Page 118: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL データ型の変換

次の例では、CHAR型変数である start_timeと finish_timeに、午前 0 時からの秒数を表す文字列値が保持されています。これらの値の差を NUMBER型変数の elapsed_timeに代入する必要があります。PL/SQL は、CHAR値を NUMBER値に自動的に変換します。

DECLARE start_time CHAR(5); finish_time CHAR(5); elapsed_time NUMBER(5);BEGIN /* Get system time as seconds past midnight. */ SELECT TO_CHAR(SYSDATE,'SSSSS') INTO start_time FROM sys.dual; -- do something /* Get system time again. */ SELECT TO_CHAR(SYSDATE,'SSSSS') INTO finish_time FROM sys.dual; /* Compute elapsed time in seconds. */ elapsed_time := finish_time - start_time; INSERT INTO results VALUES (elapsed_time, ...);END;

選択された列値を変数に代入する前に、PL/SQL は必要に応じて変換元の列のデータ型を変数のデータ型に変換します。DATE列の値を選択して VARCHAR2変数に入れる場合がこれに該当します。

同様に、変数の値をデータベース列に代入する前に、PL/SQL は必要に応じてその値を変数のデータ型からターゲット列のデータ型に変換します。PL/SQL では、どのような暗黙的変換が必要なのかが決定できない場合、コンパイル・エラーが発生します。このような場合は、データ型変換ファンクションを使用する必要があります。表 3-1 に、PL/SQL が実行できる暗黙的な変換を示します。

注意注意注意注意 :

� 表のラベル PLS_INTと BIN_INTは、PLS_INTEGER型と BINARY_INTEGER型を表しています。コード中ではこれらのラベルの省略形を使用できません。

� この表は、異なる表現を持つ型のみを示しています。CLOBと NCLOB、CHARと NCHAR、VARCHARと NVARCHAR2など、同じ表現を持つ型は、相互に代用できます。

� CLOBと NCLOBを暗黙的に変換できますが、コストが高い操作になる可能性があることに注意してください。この変換を意図的に実行するには、変換ファンクションTO_CLOBおよび TO_NCLOBを使用します。

� TIMESTAMP、TIMESTAMP WITH TIME ZONE、TIMESTAMP WITH LOCAL TIME ZONE、INTERVAL DAY TO SECONDおよび INTERVAL YEAR TO MONTHは、いずれも DATE型と同じ規則を使用して変換できます。ただし、これらの型は内部表現が異なるため、常に相互に変換できるとはかぎりません。様々な日付および時刻型間の暗黙的な変換の詳細は、『Oracle Database SQL リファレンス』を参照してください。

3-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 119: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL データ型の変換

値が実際に変換可能であるかどうかは、ユーザーが自分で確認する必要があります。たとえば、'02-JUN-92'という CHAR型の値は DATE型に変換できますが、'YESTERDAY'という CHAR型の値は DATE型に変換できません。同様に、英字を含んでいる VARCHAR2型の値は NUMBER値に変換できません。

暗黙的変換と明示的変換の選択暗黙的変換と明示的変換の選択暗黙的変換と明示的変換の選択暗黙的変換と明示的変換の選択データ型の暗黙的変換に頼るプログラミング習慣は、処理の低速化が発生したり、将来のソフトウェアで変換規則が変更される可能性があるため、好ましくありません。暗黙的変換は状況依存であるため、結果を常に予測できるとはかぎりません。信頼性とメンテナンス性を高めるために、データ型変換ファンクションを使用してください。

DATE の値の値の値の値DATE列の値を選択して CHAR型変数または VARCHAR2型変数に入れる場合、PL/SQL は内部バイナリ値を文字値に変換する必要があります。このとき、PL/SQL は、文字列をデフォルトの日付書式で戻すファンクション TO_CHARをコールします。時刻やユリウス日付などの情報を得るには、書式マスクを使用して TO_CHARをコールします。

CHAR型または VARCHAR2型の値を DATE型の列に挿入する場合にも変換が必要です。PL/SQL は、デフォルトの日付書式を期待するファンクション TO_DATEをコールします。他の書式の日付を挿入するには、書式マスクを使用して TO_DATEをコールします。

表表表表 3-1 暗黙的な変換暗黙的な変換暗黙的な変換暗黙的な変換

BIN_INT BLOB CHAR CLOB DATE LONG NUMBER PLS_INT RAW UROWID VARCHAR2

BIN_INT X X X X X

BLOB X

CHAR X X X X X X X X X

CLOB X X

DATE X X X

LONG X X X

NUMBER X X X X X

PLS_INT X X X X X

RAW X X X X

UROWID X X

VARCHAR2 X X X X X X X X X

PL/SQL のデータ型 3-25

Page 120: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL データ型の変換

RAW およびおよびおよびおよび LONG RAW の値の値の値の値RAW型または LONG RAW型の列の値を選択して CHAR型変数または VARCHAR2型変数に入れる場合、PL/SQL は内部バイナリ値を文字値に変換する必要があります。この場合、PL/SQL は RAW型データまたは LONG RAW型データの各バイナリ・バイトを文字のペアとして戻します。個々の文字はニブル(半バイト)の 16 進値を表します。たとえば、PL/SQLはバイナリ・バイト 11111111 を文字のペア 'FF'として戻します。ファンクションRAWTOHEXも同じ変換を実行します。

CHAR型または VARCHAR2型の値を RAW型または LONG RAW型の列に挿入する場合にも変換が必要です。変数中の文字のペアは、いずれもバイナリ・バイトの 16 進値を表している必要があります。一致していない場合は、PL/SQL により例外が呼び出されます。

3-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 121: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の制御構造の

4

PL/SQL の制御構造の使用の制御構造の使用の制御構造の使用の制御構造の使用

この章では、PL/SQL プログラムの制御の流れを構造化する方法を示します。PL/SQL で提供される条件テスト、ループおよび分岐を使用すると、優れた構造を持つプログラムを作成できます。

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

� PL/SQL の制御構造の概要(4-2 ページ)

� 条件テスト : IF 文および CASE 文(4-2 ページ)

� ループの反復の制御 : LOOP 文と EXIT 文(4-8 ページ)

� 順次制御 : GOTO 文と NULL 文(4-15 ページ)

使用 4-1

Page 122: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の制御構造の概要

PL/SQL の制御構造の概要の制御構造の概要の制御構造の概要の制御構造の概要図 4-1 に、手続き型コンピュータ・プログラムで使用される基本制御構造を示します。

図図図図 4-1 制御構造制御構造制御構造制御構造

選択構造は、条件をテストし、条件の真偽に応じて一連の文を実行します。条件条件条件条件とは、ブール値(TRUEまたは FALSE)を戻す任意の変数または式です。反復構造は、ある条件が真の間、一連の文を繰り返して実行します。順次構造は、一連の文を、出現する順番にそのまま実行します。

条件テスト条件テスト条件テスト条件テスト : IF 文および文および文および文および CASE 文文文文IF文は、条件の値に応じて、異なる一連の文を実行します。IF文には、IF-THEN、IF-THEN-ELSEおよび IF-THEN-ELSIFの 3 つの形式があります。

CASE文は、単一の条件を評価して多数の代替アクションから選択するコンパクトな手段です。3 つ以上の選択肢がある場合は、CASE文が有効です。

IF-THEN 文の使用文の使用文の使用文の使用IF文の も単純な形式である IF-THEN は、キーワード THENと END IF(ENDIFではない)によって囲まれた一連の文に条件を関連付けます。

IF condition THEN sequence_of_statementsEND IF;

4-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 123: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

条件テスト : IF 文および CASE 文

一連の文は、条件が TRUE に評価された場合にのみ実行されます。条件が FALSE またはNULL に評価されると、IF文は何も実行しません。いずれの場合も、制御は次の文に渡されます。

IF sales > quota THEN compute_bonus(empid); UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id;END IF;

短い IF文は 1 つの行に書くことができます。

IF x > y THEN high := x; END IF;

IF-THEN-ELSE 文の使用文の使用文の使用文の使用IF文の 2 つ目の形式では、キーワード ELSEが追加され、その後に一連の代替文を続けます。

IF condition THEN sequence_of_statements1ELSE sequence_of_statements2END IF;

ELSE句の中の文は、条件が FALSE または NULL に評価された場合にのみ実行されます。IF-THEN-ELSE文を使用すると、一連の文のどちらかが確実に実行されます。次の例では、条件が TRUE の場合に 初の UPDATE文が実行され、条件が FALSE または NULL の場合に2 番目の UPDATE文が実行されます。

IF trans_type = 'CR' THEN UPDATE accounts SET balance = balance + credit WHERE ...ELSE UPDATE accounts SET balance = balance - debit WHERE ...END IF;

IF文はネストできます。

IF trans_type = 'CR' THEN UPDATE accounts SET balance = balance + credit WHERE ...ELSE IF new_balance >= minimum_balance THEN UPDATE accounts SET balance = balance - debit WHERE ... ELSE RAISE insufficient_funds; END IF;END IF;

PL/SQL の制御構造の使用 4-3

Page 124: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

条件テスト : IF 文および CASE 文

IF-THEN-ELSEIF 文の使用文の使用文の使用文の使用複数の選択肢から選択する必要がある場合があります。(ELSEIFまたは ELSE IFではなく)キーワード ELSIFを使用すると、条件を追加できます。

IF condition1 THEN sequence_of_statements1ELSIF condition2 THEN sequence_of_statements2ELSE sequence_of_statements3END IF;

条件が FALSE または NULL に評価されると、ELSIF句は別の条件をテストします。IF文は任意の数の ELSIF句を持つことができます。 後の ELSE句はオプションです。条件は上から下に向かって 1 つずつ評価されます。いずれかの条件が TRUE に評価されると、それに付随する一連の文が実行され、制御は次の文に移ります。すべての条件が FALSE またはNULL に評価されると、ELSE句の一連の文が実行されます。次の例を考えます。

BEGIN IF sales > 50000 THEN bonus := 1500; ELSIF sales > 35000 THEN bonus := 500; ELSE bonus := 100; END IF; INSERT INTO payroll VALUES (emp_id, bonus, ...);END;

salesの値が 50000 よりも大きい場合は、1 番目と 2 番目の条件が TRUE になります。ただし、2 番目の条件はテストされないため、bonusには 1500 という正しい値が代入されます。1 番目の条件が TRUE に評価されると、それに付随する文が実行され、制御は INSERT文に移ります。

CASE 文の使用文の使用文の使用文の使用IF文と同様に、CASE文では一連の文を選択して実行できます。ただし、CASE文では、順序を選択するために複数のブール式ではなく選択子を使用します。(選択子は複数の選択肢から 1 つ選択するために値が使用される式です。第 2 章を参照してください。)IF文とCASE文を比較するために、学業成績の説明を出力する次のコードを考えます。

IF grade = 'A' THEN dbms_output.put_line('Excellent');ELSIF grade = 'B' THEN dbms_output.put_line('Very Good');ELSIF grade = 'C' THEN dbms_output.put_line('Good');

4-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 125: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

条件テスト : IF 文および CASE 文

ELSIF grade = 'D' THEN dbms_output. put_line('Fair');ELSIF grade = 'F' THEN dbms_output.put_line('Poor');ELSE dbms_output.put_line('No such grade');END IF;

5 つのブール式があることに注意してください。各インスタンスで、同じ変数 gradeが 5 つの値 'A'、'B'、'C'、'D'または 'F'のどれかをテストしています。CASE文を使用して、前述のコードを次のように書き直します。

CASE grade WHEN 'A' THEN dbms_output.put_line('Excellent'); WHEN 'B' THEN dbms_output.put_line('Very Good'); WHEN 'C' THEN dbms_output.put_line('Good'); WHEN 'D' THEN dbms_output.put_line('Fair'); WHEN 'F' THEN dbms_output.put_line('Poor'); ELSE dbms_output.put_line('No such grade');END CASE;

CASE文の方が読みやすく効率的です。長い IF-THEN-ELSIF文はできるかぎり CASE文として書き直してください。

CASE文は、キーワード CASEで始まります。キーワードの後に選択子(前述の例では変数grade)があります。選択子式は、どんなに複雑でもかまいません。たとえば、ファンクション・コールを含めることができます。ただし、通常は、1 個の変数で構成されています。選択子式が評価されるのは 1 度のみです。生成される値は、BLOB、BFILE、オブジェクト型、PL/SQL レコード、索引付き表または VARRAY、ネストした表以外であれば、どのような PL/SQL データ型でもかまいません。

選択子の後に 1 つ以上の WHEN句があり、各句が順番にチェックされます。選択子の値によって、どの句が実行されるかが決定されます。選択子の値が WHEN句の式の値と等しければ、その WHEN句が実行されます。たとえば、 後の例では、gradeが 'C'であれば、'Good'が出力されます。実行が失敗することはなく、WHEN句が 1 つでも実行されると、制御が次の文に渡されます。

ELSE句の機能は、IF文の ELSE句に似ています。前述の例では、学年が WHEN句のオプションの 1 つでなければ、ELSE句が選択され、'No such grade'という句が出力されます。ELSE句はオプションです。ただし、ELSE句を省略すると、PL/SQL では次の暗黙的なELSE句が追加されます。

ELSE RAISE CASE_NOT_FOUND;

ELSE句を省略しても、常にデフォルト・アクションがあります。CASE文がどの WHEN句にも一致せず、ELSE句を省略している場合、PL/SQL は事前定義された例外CASE_NOT_FOUNDを呼び出します。

PL/SQL の制御構造の使用 4-5

Page 126: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

条件テスト : IF 文および CASE 文

CASE文は、キーワード END CASEで終了します。この 2 つのキーワードは、空白で区切る必要があります。CASE文の書式は、次のとおりです。

[<<label_name>>]CASE selector WHEN expression1 THEN sequence_of_statements1; WHEN expression2 THEN sequence_of_statements2; ... WHEN expressionN THEN sequence_of_statementsN; [ELSE sequence_of_statementsN+1;]END CASE [label_name];

PL/SQL ブロックと同様に、CASE文にもラベルを付けることができます。ラベルは二重の山カッコで囲んだ未宣言の識別子で、CASE文の先頭に置きます。オプションとして、CASE文の末尾にもラベル名を付けることができます。

CASE文の実行中に呼び出された例外は、通常の方法で処理されます。つまり、通常の実行は中止され、PL/SQL ブロックまたはサブプログラムの例外処理部に制御が移ります。

CASE文は CASE式の代替であり、各 WHEN句が式になっています。詳細は、2-32 ページの「CASE 式」を参照してください。

検索検索検索検索 CASE 文文文文PL/SQL には、次の書式の検索 CASE文も用意されています。

[<<label_name>>]CASE WHEN search_condition1 THEN sequence_of_statements1; WHEN search_condition2 THEN sequence_of_statements2; ... WHEN search_conditionN THEN sequence_of_statementsN; [ELSE sequence_of_statementsN+1;]END CASE [label_name];

検索 CASE文には選択子はありません。また、WHEN句には、任意の型の値になる式ではなく、ブール値になる検索条件が含まれています。次に例を示します。

CASE WHEN grade = 'A' THEN dbms_output.put_line('Excellent'); WHEN grade = 'B' THEN dbms_output.put_line('Very Good'); WHEN grade = 'C' THEN dbms_output.put_line('Good'); WHEN grade = 'D' THEN dbms_output.put_line('Fair'); WHEN grade = 'F' THEN dbms_output.put_line('Poor'); ELSE dbms_output.put_line('No such grade');END CASE;

4-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 127: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

条件テスト : IF 文および CASE 文

検索条件は順番に評価されます。各検索条件のブール値によって、どの WHEN句が実行されるかが決定されます。検索条件が TRUEになると、その WHEN句が実行されます。WHEN句が 1 つでも実行されると、制御が次の文に渡されるため、後続の検索条件は評価されません。

TRUEになる検索条件がなければ、ELSE句が実行されます。ELSE句はオプションです。ただし、ELSE句を省略すると、PL/SQL では次の暗黙的な ELSE句が追加されます。

ELSE RAISE CASE_NOT_FOUND;

検索 CASE文の実行中に呼び出された例外は、通常の方法で処理されます。つまり、通常の実行は中止され、PL/SQL ブロックまたはサブプログラムの例外処理部に制御が移ります。

PL/SQL 条件文のガイドライン条件文のガイドライン条件文のガイドライン条件文のガイドライン次の例のような IF文の使用は避けてください。

IF new_balance < minimum_balance THEN overdrawn := TRUE;ELSE overdrawn := FALSE;END IF;...IF overdrawn = TRUE THEN RAISE insufficient_funds;END IF;

論理式の値は論理変数に直接代入できます。1 番目の IF文は、次のように単純な代入に置き換えることができます。

overdrawn := new_balance < minimum_balance;

ブール変数はそれ自身が TRUE または FALSE です。2 番目の IF文の条件は、次のように単純化できます。

IF overdrawn THEN ...

PL/SQL の制御構造の使用 4-7

Page 128: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

可能ならば、IF文をネストするのではなく、ELSIF句を使用してください。それによって、わかりやすく、理解しやすいコードになります。次の IF文を比較してください。

IF condition1 THEN | IF condition1 THEN statement1; | statement1; ELSE | ELSIF condition2 THEN IF condition2 THEN | statement2; statement2; | ELSIF condition3 THEN ELSE | statement3; IF condition3 THEN | END IF; statement3; | END IF; | END IF; |END IF; |

これらの文は論理的に等価ですが、2 番目の文の方が論理が明快です。

単一の式を複数の値と比較する場合は、IFと ELSIF句の組合せのかわりに単一の CASE文を使用すると、論理を簡素化できます。

ループの反復の制御ループの反復の制御ループの反復の制御ループの反復の制御 : LOOP 文と文と文と文と EXIT 文文文文LOOP文は一連の文を複数回実行します。LOOP文には、LOOP、WHILE-LOOPおよびFOR-LOOPの 3 つの形式があります。

LOOP 文の使用文の使用文の使用文の使用LOOP文の も単純な形式は、キーワード LOOPと END LOOPで一連の文を囲む基本ループです。次に例を示します。

LOOP sequence_of_statementsEND LOOP;

ループが繰り返されるたびに一連の文が実行され、制御がループの先頭に戻ります。EXIT文は、ループを終了し無限ループを防ぐために使用します。ループの中では、任意の場所に1 つまたは複数の EXIT文を置くことができます。ただし、ループの外には置くことができません。EXIT文には、EXITおよび EXIT-WHENの 2 つの形式があります。

4-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 129: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

EXIT 文の使用文の使用文の使用文の使用EXIT文はループを無条件に終了させます。EXIT文が現れると、ループはただちに終了し、制御は次の文に移ります。

LOOP IF credit_rating < 3 THEN EXIT; -- exit loop immediately END IF;END LOOP;-- control resumes here

EXIT文はループの中に置くことに注意してください。PL/SQL ブロックを通常終了より前の段階で終了させる場合は、RETURN文を使用します。詳細は、8-6 ページの「RETURN 文の使用」を参照してください。

EXIT-WHEN 文の使用文の使用文の使用文の使用EXIT-WHEN文を使用すると、ループを条件に合わせて終了できます。EXIT文が見つかると、WHEN句の中の条件が評価されます。条件の評価結果が TRUE ならば、ループは終了し、制御はそのループの後の文に移ります。

LOOP FETCH c1 INTO ... EXIT WHEN c1%NOTFOUND; -- exit loop if condition is true ...END LOOP;CLOSE c1;

条件の評価結果が TRUE になるまで、ループは終了できません。ループの中で条件の値を変更する必要があります。前述の例で、FETCH文が行を戻すと、条件は FALSE に評価されます。FETCH文が行を戻すことに失敗した場合、条件は TRUE に評価され、ループは終了し、制御は CLOSE文に移ります。

EXIT-WHEN文は単純な IF文のかわりとして使用できます。たとえば、次の 2 つの文を比較してください。

IF count > 100 THEN | EXIT WHEN count > 100; EXIT; |END IF; |

この 2 つの文は論理的に等価ですが、EXIT-WHEN文の方がわかりやすく、理解しやすくなっています。

PL/SQL の制御構造の使用 4-9

Page 130: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

PL/SQL ループのラベル付けループのラベル付けループのラベル付けループのラベル付けPL/SQL ブロックと同様に、ループにもラベルを付けることができます。ラベルは二重の山カッコで囲んだ未宣言の識別子で、次に示すように LOOP文の先頭に置きます。

<<label_name>>LOOP sequence_of_statementsEND LOOP;

次の例のように、オプションとして、LOOP文の末尾にもラベル名を付けることができます。

<<my_loop>>LOOP ...END LOOP my_loop;

ラベル付きのループをネストする場合は、末尾のラベルを使用してわかりやすくします。

どちらの形式の EXIT文でも、カレント・ループにかぎらず、任意の外側のループも終了させることができます。これを行うには、終了する外側のループにラベルを付けます。次に示すように、EXIT文でそのラベルを使用します。

<<outer>>LOOP ... LOOP ... EXIT outer WHEN ... -- exit both loops END LOOP; ...END LOOP outer;

ラベルを付けた外側のループが、内側のループを含めて終了します。

WHILE-LOOP 文の使用文の使用文の使用文の使用WHILE-LOOP文は、条件が TRUE に評価されるかぎり、ループ本体の文を実行します。

WHILE condition LOOP sequence_of_statementsEND LOOP;

4-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 131: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

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

WHILE total <= 25000 LOOP SELECT sal INTO salary FROM emp WHERE ... total := total + salary;END LOOP;

反復の回数は条件に依存し、ループが終了するまでわかりません。条件はループの先頭でテストされるため、一連の文が一度も実行されない可能性もあります。前述の例で totalの初期値が 25000 よりも大きい場合、条件が FALSE に評価されてループは実行されません。

いくつかの言語は、条件をループの先頭ではなく末尾でテストする LOOP UNTIL構造またはREPEAT UNTIL構造を持っています。そのため、一連の文は 1 回以上実行されます。PL/SQL での等価のコードを次に示します。

LOOP sequence_of_statements EXIT WHEN boolean_expression;END LOOP;

WHILEループが 1 回以上実行されるようにするには、初期化済のブール変数を条件の中で使用します。

done := FALSE;WHILE NOT done LOOP sequence_of_statements done := boolean_expression;END LOOP;

ループの中の文でブール変数に新しい値を代入して、無限ループを回避します。

FOR-LOOP 文の使用文の使用文の使用文の使用単純な FORループは、指定された整数の範囲内でループを繰り返し実行します。反復の回数はループに入る前からわかっています。二重ドット(..)は、範囲演算子です。

FOR counter IN [REVERSE] lower_bound..higher_bound LOOP sequence_of_statementsEND LOOP;

繰返しの範囲は FORループに入った段階で評価され、それ以降は評価されません。

PL/SQL の制御構造の使用 4-11

Page 132: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

次の例に示すように、一連の文は範囲中の整数 1 つについて 1 回実行されます。繰り返しが1 回行われるたびに、ループ・カウンタが 1 つ増えます。

FOR i IN 1..3 LOOP -- assign the values 1,2,3 to i sequence_of_statements -- executes three timesEND LOOP;

下限と上限が等しければ、ループ本体は 1 回のみ実行されます。

FOR i IN 3..3 LOOP -- assign the value 3 to i sequence_of_statements -- executes one timeEND LOOP;

デフォルトでは、反復は下限から上限の向きに進みます。キーワード REVERSEを使用した場合、反復は上限から下限に下向きに進みます。繰返しが 1 回行われるたびに、ループ・カウンタが 1 つ減ります。この場合でも、範囲の上限と下限は(降順ではなく)昇順に書きます。

FOR i IN REVERSE 1..3 LOOP -- assign the values 3,2,1 to i sequence_of_statements -- executes three timesEND LOOP;

FORループの中では、ループ・カウンタを参照できますが、変更することはできません。

FOR ctr IN 1..10 LOOP IF NOT finished THEN INSERT INTO ... VALUES (ctr, ...); -- OK factor := ctr * 2; -- OK ELSE ctr := 10; -- not allowed END IF;END LOOP;

ヒントヒントヒントヒント : FORループで、整数の範囲のかわりに SQL 問合せを使用することをお薦めします。この手法を使用すると、単純な構文で、問合せを実行し、結果セットのすべての行を処理できます。詳細は、6-12 ページの「PL/SQL を使用したデータの問合せ : 暗黙カーソルの FORループ」を参照してください。

PL/SQL ループの反復方法ループの反復方法ループの反復方法ループの反復方法ループ範囲の境界にはリテラル、変数または式を使用できますが、整数に評価されるものにする必要があります。それ以外の場合、PL/SQL は事前定義の例外 VALUE_ERRORを呼び出します。下限は 1 である必要はありませんが、ループ・カウンタの増分値(または減分値)は 1 である必要があります。

j IN -5..5k IN REVERSE first..laststep IN 0..TRUNC(high/low) * 2

4-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 133: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

内部的に、PL/SQL は PLS_INTEGER一時変数に境界の値を代入します。さらに、必要に応じてその値を も近い整数に四捨五入します。PLS_INTEGERの大きさの範囲は、-2**31 ~ 2**31 です。範囲外の数値の場合、PL/SQL が代入しようとすると、数値オーバーフローのエラーが発生します。

言語によっては、STEP句を使用して異なる増分値(たとえば、1 ではなく 5)を指定できるものがあります。PL/SQL はこのような構造を持っていませんが、作成するのは簡単です。FORループの内部で、ループ・カウンタへの各参照に新しい増分値を乗じます。次の例では、本日の日付を索引付き表の要素 5、10、および 15 に代入します。

DECLARE TYPE DateList IS TABLE OF DATE INDEX BY BINARY_INTEGER; dates DateList; k CONSTANT INTEGER := 5; -- set new incrementBEGIN FOR j IN 1..3 LOOP dates(j*k) := SYSDATE; -- multiply loop counter by increment END LOOP; ...END;

ループの動的な範囲ループの動的な範囲ループの動的な範囲ループの動的な範囲PL/SQL では、範囲に変数を使用することでループの範囲を実行時に指定できます。

SELECT COUNT(empno) INTO emp_count FROM emp;FOR i IN 1..emp_count LOOP ...END LOOP;

ループ範囲の下限が、上限より大きい整数であると評価された場合、ループ本体は実行されず、制御は次の文に移ります。

-- limit becomes 1FOR i IN 2..limit LOOP sequence_of_statements -- executes zero timesEND LOOP;-- control passes here

ループ・カウンタ変数の有効範囲ループ・カウンタ変数の有効範囲ループ・カウンタ変数の有効範囲ループ・カウンタ変数の有効範囲ループ・カウンタはループの中でしか定義されません。そのため、その変数名をループの外側からは参照できません。ループが終了すると、ループ・カウンタは未定義になります。

FOR ctr IN 1..10 LOOP ...END LOOP;sum := ctr - 1; -- not allowed

PL/SQL の制御構造の使用 4-13

Page 134: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ループの反復の制御 : LOOP 文と EXIT 文

ループ・カウンタは INTEGER型のローカル変数として暗黙的に宣言されているため、ループ・カウンタを宣言する必要はありません。ローカル宣言はグローバル宣言を隠すため、も安全な方法は、既存の変数の名前を使用しないことです。

DECLARE ctr INTEGER := 3;BEGIN ... FOR ctr IN 1..25 LOOP ... IF ctr > 10 THEN ... -- Refers to loop counter END LOOP;-- After the loop, ctr refers to the original variable with value 3.END;

この例でグローバル変数を使用する場合は、次のようにラベルとドット表記法を使用する必要があります。

<<main>>DECLARE ctr INTEGER; ...BEGIN ... FOR ctr IN 1..25 LOOP ... IF main.ctr > 10 THEN -- refers to global variable ... END IF; END LOOP;END main;

ネストされた FORループにも同じ有効範囲規則が適用されます。次の例を考えてみてください。どちらのループ・カウンタも同じ名前を持っています。内側のループから外側のループ・カウンタを参照する場合は、次のようにラベルとドット表記法を使用します。

<<outer>>FOR step IN 1..25 LOOP FOR step IN 1..10 LOOP ... IF outer.step > 15 THEN ... END LOOP;END LOOP outer;

4-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 135: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

順次制御 : GOTO 文と NULL 文

FOR ループでのループでのループでのループでの EXIT 文の使用文の使用文の使用文の使用EXIT文を使用すると、FORループを途中で終了させることができます。たとえば、次のループは通常は 10 回実行されますが、FETCH文が行を戻さなくなると、ループはそれまで何回実行されていてもただちに終了します。

FOR j IN 1..10 LOOP FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; ...END LOOP;

ネストされた FORループから途中で出る必要があるとします。カレント・ループのみでなく、外側のループも終了するには、終了する外側のループにラベルを付け、EXIT文でそのラベルを使用します。

<<outer>>FOR i IN 1..5 LOOP ... FOR j IN 1..10 LOOP FETCH c1 INTO emp_rec; EXIT outer WHEN c1%NOTFOUND; -- exit both FOR loops ... END LOOP;END LOOP outer;-- control passes here

順次制御順次制御順次制御順次制御 : GOTO 文と文と文と文と NULL 文文文文GOTO文と NULL文は、PL/SQL プログラミングにとって IF文や LOOP文ほど重要なものではありません。通常、GOTO文は必要ありません。ただし、GOTO 文を使用すると論理を単純化できる場合もあります。NULL文には、条件文の意味とアクションを明確にすることによって、コードをわかりやすくする効果があります。

GOTO文を多用すると、コードの理解やメンテナンスが困難になる可能性があります。GOTO文の使用は 小限にしてください。たとえば、深くネストされた構造からエラー処理ルーチンに分岐する場合は、GOTO文を使用するのではなく、例外を呼び出してください。PL/SQL の例外処理メカニズムについては、第 10 章「PL/SQL エラーの処理」を参照してください。

PL/SQL の制御構造の使用 4-15

Page 136: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

順次制御 : GOTO 文と NULL 文

GOTO 文の使用文の使用文の使用文の使用GOTO文はラベルに無条件に分岐する場合に使用します。ラベルは有効範囲の中で他と重複しないもので、実行可能文か PL/SQL ブロックの前に置かれている必要があります。GOTO文が実行されると、ラベルが付けられた文またはブロックに制御が移ります。次の例では、一連の文の下の方にある実行可能文に制御が渡されています。

BEGIN ... GOTO insert_row; ... <<insert_row>> INSERT INTO emp VALUES ...END;

次の例では、一連の文の上の方にある PL/SQL ブロックに制御が渡されています。

DECLARE x NUMBER := 0;BEGIN <<increment_x>> BEGIN x := x + 1; END; IF x < 10 THEN GOTO increment_x; END IF;END;

次の例に示すラベル end_loopは、実行可能文の前に置かれていないため、使用できません。

DECLARE done BOOLEAN;BEGIN FOR i IN 1..50 LOOP IF done THEN GOTO end_loop; END IF; <<end_loop>> -- not allowed END LOOP; -- not an executable statementEND;

4-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 137: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

順次制御 : GOTO 文と NULL 文

このコードを修正するには、NULL文を追加します。

FOR i IN 1..50 LOOP IF done THEN GOTO end_loop; END IF; ...<<end_loop>>NULL; -- an executable statementEND LOOP;

次の例に示すように、GOTO文でカレント・ブロックから外側のブロックに分岐できます。

DECLARE my_ename CHAR(10);BEGIN <<get_name>> SELECT ename INTO my_ename FROM emp WHERE ... BEGIN GOTO get_name; -- branch to enclosing block END;END;

この GOTO文では、参照されたラベルが置かれている 初の外側のブロックに分岐します。

GOTO 文の制限文の制限文の制限文の制限GOTO文の宛先として使用できないものがあります。特に、GOTO文は IF文、CASE文、LOOP文またはサブブロックには分岐できません。たとえば、次の GOTO文は誤りです。

BEGIN GOTO update_row; -- can't branch into IF statement IF valid THEN <<update_row>> UPDATE emp SET ... END IF;END;

GOTO文では、ある IF文の句から句へ分岐したり、ある CASE文の WHEN句から別の句へ分岐することはできません。

GOTO文では、外部のブロックからサブブロック(内側の BEGIN-ENDブロック)には分岐できません。

GOTO文では、サブプログラムの外に分岐できません。サブプログラムを途中で終了するには、RETURN文を使用するか、または GOTO文を使用してサブプログラムの終了直前の場所に分岐します。

PL/SQL の制御構造の使用 4-17

Page 138: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

順次制御 : GOTO 文と NULL 文

GOTO文では、例外ハンドラからカレント・ブロック BEGIN-ENDに分岐できません。ただし、例外ハンドラから外側のブロックに分岐することはできます。

NULL 文の使用文の使用文の使用文の使用NULL文は、何も行わずに制御を次の文に渡します。(言語によっては、このような命令がNOOP と呼ばれています。)

NULL文を使用すると、考慮はするがアクションが必要ないことを示すことができます。次の例では、NULL文によって、名前のない例外ではアクションを起こさないことを示しています。

EXCEPTION WHEN ZERO_DIVIDE THEN ROLLBACK; WHEN VALUE_ERROR THEN INSERT INTO errors VALUES ... COMMIT; WHEN OTHERS THEN NULL;END;

NULL文を使用すると、プレースホルダやスタブ・プロシージャを簡単に作成できます。次の例では、NULL文を使用してプロシージャをコンパイルしています。実際の本体は、後で挿入できます。

PROCEDURE debit_account (acct_id INTEGER, amount REAL) ISBEGIN NULL;END debit_account;

4-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 139: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコレクションおよびレコードの

5

PL/SQL のコレクションおよびレコードの使用のコレクションおよびレコードの使用のコレクションおよびレコードの使用のコレクションおよびレコードの使用

多くのプログラミング手法では、配列、バッグ、リスト、ネストした表、セット、ツリーなどのコレクション型を使用します。PL/SQL のデータ型 TABLEおよび VARRAYを使用すると、データベース・アプリケーション内でこれらの型をモデル化できます。これによって、ネストした表、結合配列および可変サイズの配列を宣言できます。この章では、データの集まり(コレクション)をローカル変数として参照または操作する方法を示します。また、RECORDデータ型を使用して、関連する様々な型の値を 1 つの論理単位として操作する方法についても説明します。

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

� コレクション(5-2 ページ)

� 使用する PL/SQL コレクション型の選択(5-5 ページ)

� コレクション型の定義(5-7 ページ)

� PL/SQL のコレクション変数の宣言(5-10 ページ)

� コレクションの初期化および参照(5-13 ページ)

� コレクションの代入(5-17 ページ)

� コレクションの比較(5-20 ページ)

� SQL 文での PL/SQL コレクションの使用(5-23 ページ)

� コレクション・メソッドの使用(5-30 ページ)

� コレクション例外の回避(5-39 ページ)

� PL/SQL レコード(5-41 ページ)

� レコードの定義と宣言(5-41 ページ)

� レコードへの値の代入(5-44 ページ)

使用 5-1

Page 140: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

コレクションコレクションコレクションコレクションコレクションコレクションコレクションコレクションは、すべて同じ型の要素の順序付きグループです。コレクションは、リスト、配列および標準的なプログラミング・アルゴリズムで使用される他のデータ型を包含した一般的な概念です。各要素は、一意の添字によってアドレスが付けられます。

PL/SQL には、次のコレクション型が用意されています。

� 結合配列結合配列結合配列結合配列は、索引付き表索引付き表索引付き表索引付き表とも呼ばれ、添字の値に任意の数字または文字列を使用して要素を参照できます。(他のプログラミング言語でのハッシュ表ハッシュ表ハッシュ表ハッシュ表に似ています。)

� ネストした表ネストした表ネストした表ネストした表は、任意の数の要素を保持します。ネストした表では、添字に連番が使用されます。等価の SQL の型を定義すると、ネストした表をデータベース表に格納し、SQL を介して操作できます。

� VARRAY(可変サイズの配列)は、固定数の要素を保持します(ただし、要素の数は実行時に変更できます)。VARRAY では、添字に連番を使用します。等価の SQL の型を定義すると、データベース表に VARRAY を格納できます。VARRAY は SQL を介して格納および取得できますが、ネストした表に比べると柔軟性は低くなります。

コレクションは 1 次元のみですが、コレクションを要素に持つコレクションを作成すると、多次元配列のモデルを作成できます。

アプリケーションでコレクションを使用するには、1 つ以上の PL/SQL の型を定義し、それらの型の変数を定義します。コレクション型は、プロシージャ、ファンクションまたはパッケージで定義できます。ストアド・サブプログラムに、コレクションの変数をパラメータとして渡すことができます。

単一の値よりも複雑なデータを参照するために、PL/SQL レコードまたは SQL オブジェクト型をコレクションに格納できます。ネストした表と VARRAY は、オブジェクト型の属性にすることもできます。

ネストした表ネストした表ネストした表ネストした表PL/SQL のネストした表は、一連の値を表します。これは、上限のない 1 次元配列と考えることができます。要素にネストした表を持つネストした表を作成すると、多次元配列のモデルを作成できます。

データベース内では、ネストした表は一連の値を保持する列の型と考えられます。Oracleは、ネストした表の行を特に順序付けずに格納します。ネストした表をデータベースからPL/SQL 変数の中に取り出すと、それらの行に 1 から始まる連続した添字が付けられます。これによって、個々の行に配列のようにアクセスできます。

ネストした表と配列には重要な相違点が 2 つあります。

1. 配列には固定の上限がありますが、ネストした表には限界がありません(図 5-1 を参照)。ネストした表のサイズは動的に大きくできます。

5-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 141: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

2. 配列は常に密です(添字が連続しています)が、ネストした表は添字が連続していない場合があります。ネストした表も 初は密ですが、疎にすることができます(つまり添字が連続していなくてもかまいません)。組込みプロシージャ DELETEを使用すると、ネストした表から要素を削除できます。組込みファンクション NEXTを使用すると、順序に欠番が生じる場合でも、ネストした表のすべての添字に対して反復処理を実行できます。

図図図図 5-1 配列とネストした表との相違点配列とネストした表との相違点配列とネストした表との相違点配列とネストした表との相違点

VARRAYVARRAY型の項目は、VARRAY と呼ばれます。VARRAY を使用すると、配列操作の個々の要素を参照したり、コレクションを全体として操作することができます。要素を参照するには、標準的な添字構文を使用します(図 5-2 を参照)。たとえば、Grade(3)は、Gradesという VARRAY の 3 番目の要素を参照します。

図図図図 5-2 サイズサイズサイズサイズ 10 のののの VARRAY

VARRAY には 大サイズがあり、このサイズを型定義で指定します。VARRAY の索引には、1 に固定されている下限と、拡張可能な上限があります。たとえば、VARRAY Gradesの現在の上限は 7 ですが、 大 10 まで拡張できます。したがって、VARRAY に入れることのできる要素の数は、0(空の場合)個から型定義で指定された 大値まで変更できます。

PL/SQL のコレクションおよびレコードの使用 5-3

Page 142: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

結合配列(索引付き表)結合配列(索引付き表)結合配列(索引付き表)結合配列(索引付き表)結合配列は、キーと値のペアのセットです。各キーは一意で、配列内の対応する値を検索するために使用されます。キーは、整数または文字列にできます。

初めてキーを使用して値を代入すると、そのキーが結合配列に追加されます。その後、同じキーを使用して値を代入すると、同じエントリが更新されます。一意のキーを選択することが重要です。たとえば、データベース表の主キー、数値のハッシュ関数、複数の文字列を連結した一意の文字列の値などを、キーの値として使用できます。

次に、文字列のキーを使用した結合配列型の宣言と、この型の 2 つの配列の例を示します。

DECLARE TYPE population_type IS TABLE OF NUMBER INDEX BY VARCHAR2(64); country_population population_type; continent_population population_type; howmany NUMBER; which VARCHAR2(64);BEGIN country_population('Greenland') := 100000; -- Creates new entry country_population('Iceland') := 750000; -- Creates new entry-- Looks up value associated with a string howmany := country_population('Greenland');

continent_population('Australia') := 30000000; continent_population('Antarctica') := 1000; -- Creates new entry continent_population('Antarctica') := 1001; -- Replaces previous value

-- Returns 'Antarctica' as that comes first alphabetically. which := continent_population.FIRST;-- Returns 'Australia' as that comes last alphabetically. which := continent_population.LAST;-- Returns the value corresponding to the last key, in this-- case the population of Australia. howmany := continent_population(continent_population.LAST);END;/

結合配列は、任意のサイズのデータ・セットを表すために役立ち、配列内での要素の位置が不明でも、配列の全要素をループせずに個々の要素をすばやく参照します。単純な SQL 表のように、主キーに基づいて値を取り出すことができます。単純な参照データの一時記憶域では、結合配列によって、SQL 表に必要なディスク領域の使用やネットワーク操作を回避できます。

結合配列は、永続的なデータの格納ではなく一時的なデータを意図しているため、INSERTや SELECT INTOなどの SQL 文では使用できません。結合配列は、パッケージで型を宣言し、パッケージ本体に値を代入することで、データベース・セッションの間を永続的に維持できます。

5-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 143: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

使用する PL/SQL コレクション型の選択

グローバリゼーション設定が結合配列のグローバリゼーション設定が結合配列のグローバリゼーション設定が結合配列のグローバリゼーション設定が結合配列の VARCHAR2 キーに与える影響キーに与える影響キーに与える影響キーに与える影響VARCHAR2のキー値を持つ結合配列を使用したセッション中に、各国語またはグローバリゼーションの設定が変わると、プログラムでランタイム・エラーとなる可能性があります。たとえば、セッション中に NLS_COMP初期化パラメータや NLS_SORT初期化パラメータを変更すると、NEXTや PRIORなどのメソッドで例外が発生する可能性があります。セッション中にこれらの設定の変更が必要な場合は、必ず元の値に戻してから、結合配列での操作を実行してください。

キーに文字列を使用して結合配列を宣言する場合、その宣言では VARCHAR2型、STRING型または LONG型を使用する必要があります。結合配列を参照するためのキー値には、NCHAR型や NVARCHAR2型などの異なる型を使用できます。TO_CHARファンクションでVARCHAR2に変換できる場合は、DATEなどの型を使用することもできます。

ただし、他の型を使用する場合は、キーに使用する値の一貫性と一意性に注意してください。たとえば、NLS_DATE_FORMAT初期化パラメータが変更された場合は、SYSDATEの文字列値が変更され、その結果、array_element(SYSDATE)では、以前と異なる結果が生じます。異なる 2 つの NVARCHAR2値が、(特定の各国語キャラクタのかわりに疑問符が使用されて)同一の VARCHAR2値に変わる可能性もあります。この場合、array_element(national_string1)と array_element(national_string2)は、同一の要素を参照します。NLS_SORT初期化パラメータの末尾が _CI(大 / 小文字を区別しない比較)または _AI(アクセント記号の有無および大 / 小文字を区別しない比較)である場合、大 / 小文字、アクセント記号またはデリミタ文字の異なる 2 つの CHARまたはVARCHAR2の値も同じであるとみなされます。

データベース・リンクを使用して、リモート・データベースへのパラメータとして結合配列を渡すと、2 つのデータベースで、グローバリゼーション設定が異なる可能性があります。リモート・データベースで FIRSTや NEXTなどの操作を実行すると、文字順序が元のコレクションとは異なる場合でも、リモート・データベース自体の文字順序が使用されます。キャラクタ・セットの相違によって、一意であった 2 つのキーがリモート・データベース上では一意でない場合、プログラムは VALUE_ERROR例外を受け取ります。

使用する使用する使用する使用する PL/SQL コレクション型の選択コレクション型の選択コレクション型の選択コレクション型の選択他の言語を使用するコードまたはビジネス・ロジックがすでに存在する場合、通常は、その言語の配列を変換して、型を PL/SQL のコレクション型に直接設定できます。

� 他の言語の配列は、PL/SQL の VARRAY になります。

� 他の言語の設定およびバッグは、PL/SQL のネストした表になります。

� 他の言語のハッシュ表や他の無秩序な参照表は、PL/SQL の結合配列になります。

オリジナルのコードを記述していたり、 初からビジネス・ロジックを設計している場合は、各状況に適切なコレクション型を判断するために各コレクション型の長所を考慮してください。

PL/SQL のコレクションおよびレコードの使用 5-5

Page 144: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

使用する PL/SQL コレクション型の選択

ネストした表と結合配列の選択ネストした表と結合配列の選択ネストした表と結合配列の選択ネストした表と結合配列の選択ネストした表と結合配列(以前の索引付き表)はともに、同じような添字表記法を使用しますが、パラメータの引渡しの永続性と容易性の点で、異なる特性があります。

ネストした表はデータベースの列に格納できますが、結合配列をデータベースの列に格納することはできません。ネストした表を使用すると、通常、単一列の表とそれより大きい表を結合する必要がある SQL 操作を簡略化できます。

結合配列は、プロシージャのコールやパッケージの初期化のたびにコレクションがメモリー内に構成される、比較的小規模な参照表に適しています。結合配列のサイズには固定制限がないため、量が事前にわからない情報を収集する場合に効果的です。結合配列の添字には、負数や非連続の数字を指定したり、数字のかわりに文字列の値を使用することができるため、その索引値は柔軟性があります。

PL/SQL は、数値のキー値を使用するホスト配列と結合配列との間で自動的に変換を行います。データベース・サーバーとの間でのコレクションの受渡しには、データの値を結合配列で設定し、その結合配列を(FORALL 文または BULK COLLECT 句を使用した)バルク構成で使用することが、 も効果的な方法です。

ネストした表とネストした表とネストした表とネストした表と VARRAY との使い分けとの使い分けとの使い分けとの使い分けVARRAY が適している場合を次に示します。

� 要素の数が事前にわかっている。

� 通常、すべての要素が順番にアクセスされる。

データベースに格納されている間、VARRAY はその順序と添字を保持しています。

各 VARRAY は、それが列である表の内部(VARRAY が 4KB 未満の場合)か、同じ表領域内の表の外部(VARRAY が 4KB を超える場合)のいずれかに、単一のオブジェクトとして格納されます。VARRAY のすべての要素は、同時に更新または取得する必要があります。これは、すべての要素に対してなんらかの操作を同時に実行する場合に 適です。ただし、この方法で多数の要素を格納および取得することは、現実的ではありません。

ネストした表が適している場合を次に示します。

� 索引値が連続していない。

� 索引値に上限が事前定義されていない。

� すべての要素を同時にではなく、一部の要素を削除または更新する必要がある。

� 通常、メインの表の各行に複数のエントリを含む個別の参照表を作成し、結合問合せを介してその表にアクセスする。

ネストした表は疎密な場合があります。 後から順に項目を削除せずに、任意の要素を削除できます。

5-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 145: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション型の定義

ネストした表のデータは、個別の記憶域表記憶域表記憶域表記憶域表に格納されます。この記憶域表は、ネストした表に関連付けられた、システム生成によるデータベース表です。ネストした表にアクセスすると、データベースで記憶域表が結合されます。この記憶域表によって、ネストした表は、コレクションの一部の要素にのみ影響を与える問合せと更新に適した内容になります。

ネストした表では、データベースへの格納(またはデータベースからの取得)時に表の順序と添字が保持されないため、ネストした表の順序と添字は信頼できません。

コレクション型の定義コレクション型の定義コレクション型の定義コレクション型の定義コレクションを作成するには、コレクション型を定義した後、その型の変数を宣言します。TABLE型および VARRAY型は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で定義できます。

コレクションは、他の型や変数と同じ有効範囲とインスタンス化の規則に従います。コレクションは、ブロックまたはサブプログラムに入ったときにインスタンス化され、ブロックまたはサブプログラムが終了した時点で消滅します。パッケージの中では、そのパッケージが初めて参照された時点でコレクションのインスタンスが生成され、データベース・セッションが終わった時点で消滅します。

ネストした表ネストした表ネストした表ネストした表

ネストした表の PL/SQL データ型を定義するには、次の構文を使用します。

TYPE type_name IS TABLE OF element_type [NOT NULL];

type_nameは、コレクションを宣言するために後で使用する型指定子です。PL/SQL 内で宣言されたネストした表の場合、element_typeは、次の型を除く PL/SQL のデータ型です。

REF CURSOR

CREATE TYPE文を使用して SQL で宣言されたネストした表には、要素型に追加制約があります。次の要素型は使用できません。

BINARY_INTEGER, PLS_INTEGERBOOLEANLONG、LONG RAWNATURAL、NATURALNPOSITIVE、POSITIVENREF CURSORSIGNTYPESTRING

PL/SQL のコレクションおよびレコードの使用 5-7

Page 146: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション型の定義

VARRAYVARRAY の PL/SQL データ型を定義するには、次の構文を使用します。

TYPE type_name IS {VARRAY | VARYING ARRAY} (size_limit) OF element_type [NOT NULL];

type_nameと element_typeの意味は、ネストした表の場合と同じです。

size_limitは、配列内の 大要素数を表す正の整数リテラルです。

VARRAY型の定義では、その 大サイズを指定する必要があります。次の例では、366 個以内の日付を格納する型を定義します。

DECLARE TYPE Calendar IS VARRAY(366) OF DATE;BEGIN NULL;END;/

結合配列結合配列結合配列結合配列結合配列は、索引付き表とも呼ばれ、任意のキー値を使用して要素を挿入できます。キーは連続しなくてもかまいません。次の構文を使用します。

TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX BY [PLS_INTEGER | BINARY_INTEGER | VARCHAR2(size_limit)]; INDEX BY key_type;

key_type には、PLS_INTEGERまたは BINARY_INTEGERの数値を指定できます。VARCHAR2またはそのサブタイプ VARCHAR、STRINGまたは LONGのいずれかを指定することもできます。VARCHAR2ベースのキーを使用するには、VARCHAR2(32760)のキーの型を宣言することになる LONGの場合を除いて、キーの長さを指定する必要があります。RAW、LONG RAW、ROWID、CHARおよび CHARACTERの各型は、結合配列のキーとしては使用できません。

初期化の句は指定できません。結合配列用のコンストラクタの表記は存在しません。

VARCHAR2ベースのキーを使用する結合配列の要素を参照する場合は、TO_CHARファンクションで VARCHAR2に変換できるかぎり、DATE、TIMESTAMPなどの別の型を使用できます。

5-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 147: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション型の定義

結合配列は、主キー値を索引として使用してデータを格納できます。この場合、連続したキー値とはなりません。次の例では、添字に 1 のかわりに 100 を使用して、結合配列の 1 つの要素を作成しています。

DECLARE TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER; emp_tab EmpTabTyp;BEGIN /* Retrieve employee record. */ SELECT * INTO emp_tab(100) FROM employees WHERE employee_id = 100;END;/

PL/SQL コレクション型に相当するコレクション型に相当するコレクション型に相当するコレクション型に相当する SQL の型の定義の型の定義の型の定義の型の定義ネストした表および VARRAY をデータベース表の内部に格納するには、CREATE TYPE文を使用して SQL の型を宣言することも必要です。SQL の型は、列としてまたは SQL オブジェクト型の属性として使用できます。

PL/SQL 内で相当する型を宣言するか、PL/SQL の変数宣言で SQL の型名を使用できます。

例例例例 5-1 SQL でのネストした表の宣言でのネストした表の宣言でのネストした表の宣言でのネストした表の宣言

次の SQL*Plus スクリプトは、SQL で宣言したネストした表をオブジェクト型の属性として使用する方法を示しています。

CREATE TYPE CourseList AS TABLE OF VARCHAR2(10) -- define type/CREATE TYPE Student AS OBJECT ( -- create object id_num INTEGER(4), name VARCHAR2(25), address VARCHAR2(35), status CHAR(2), courses CourseList); -- declare nested table as attribute/

DROP TYPE Student;DROP TYPE CourseList;

識別子 coursesはネストした表全体を表します。coursesの各要素には、'Math 1020'などの大学のコース名を入れます。

PL/SQL のコレクションおよびレコードの使用 5-9

Page 148: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコレクション変数の宣言

例例例例 5-2 VARRAY 列を持つ表の作成列を持つ表の作成列を持つ表の作成列を持つ表の作成

次のスクリプトによって、VARRAY を格納するデータベースの列が作成されます。VARRAY の各要素には VARCHAR2型が格納されます。

-- Each project has a 16-character code name.-- We will store up to 50 projects at a time in a database column.CREATE TYPE ProjectList AS VARRAY(50) OF VARCHAR2(16);/CREATE TABLE department ( -- create database table dept_id NUMBER(2), name VARCHAR2(15), budget NUMBER(11,2),-- Each department can have up to 50 projects. projects ProjectList);

DROP TABLE department;DROP TYPE ProjectList;

PL/SQL のコレクション変数の宣言のコレクション変数の宣言のコレクション変数の宣言のコレクション変数の宣言コレクション型を定義した後は、その型の変数を宣言します。NUMBERなどの事前定義の型と同様に、宣言では新しい型名を使用します。

例例例例 5-3 ネストした表、ネストした表、ネストした表、ネストした表、VARRAY および結合配列の宣言および結合配列の宣言および結合配列の宣言および結合配列の宣言

DECLARE TYPE nested_type IS TABLE OF VARCHAR2(20); TYPE varray_type IS VARRAY(5) OF INTEGER; TYPE assoc_array_num_type IS TABLE OF NUMBER INDEX BY PLS_INTEGER; TYPE assoc_array_str_type IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER; TYPE assoc_array_str_type2 IS TABLE OF VARCHAR2(32) INDEX BY VARCHAR2(64); v1 nested_type; v2 varray_type; v3 assoc_array_num_type; v4 assoc_array_str_type; v5 assoc_array_str_type2;BEGIN v1 := nested_type('Arbitrary','number','of','strings'); v2 := varray_type(10, 20, 40, 80, 160); -- Up to 5 integers v3(99) := 10; -- Just start assigning to elements. v3(7) := 100; -- Subscripts can be any integer values. v4(42) := 'Cat'; -- Just start assigning to elements. v4(54) := 'Hat'; -- Subscripts can be any integer values.

5-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 149: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコレクション変数の宣言

v5('Canada') := 'North America'; -- Just start assigning to elements. v5('Greece') := 'Europe'; -- Subscripts can be string values.END;/

例例例例 5-4 %TYPE を使用したコレクションの宣言を使用したコレクションの宣言を使用したコレクションの宣言を使用したコレクションの宣言

%TYPEを使用すると、事前に宣言したコレクションのデータ型を指定できます。この指定によって、コレクションの定義を変更すると、要素の数または要素の型に依存している他の変数が自動的に更新されます。

DECLARE TYPE Few_Colors IS VARRAY(10) OF VARCHAR2(20); TYPE Many_Colors IS VARRAY(100) OF VARCHAR2(64); some_colors Few_Colors;-- If we change the type of SOME_COLORS from FEW_COLORS to MANY_COLORS,-- RAINBOW and CRAYONS will use the same type when this block is recompiled. rainbow some_colors%TYPE; crayons some_colors%TYPE;BEGIN NULL;END;/

例例例例 5-5 ネストした表としてのプロシージャのパラメータの宣言ネストした表としてのプロシージャのパラメータの宣言ネストした表としてのプロシージャのパラメータの宣言ネストした表としてのプロシージャのパラメータの宣言

コレクションは、ファンクションおよびプロシージャの仮パラメータとして宣言できます。これによって、コレクションをストアド・サブプログラムに渡したり、あるサブプログラムから別のサブプログラムに渡すことができます。次の例では、ネストした表をパッケージ・プロシージャのパラメータとして宣言しています。

CREATE PACKAGE personnel AS TYPE Staff_List IS TABLE OF employees.employee_id%TYPE; PROCEDURE award_bonuses (who_gets_em IN Staff_List);END personnel;/

DROP PACKAGE personnel;

パッケージ外部から PERSONNEL.AWARD_BONUSESをコールするには、PERSONNEL.STAFF型の変数を宣言し、その変数をパラメータとして渡します。

ファンクション仕様部の RETURN句の中にコレクション型を指定することもできます。

PL/SQL のコレクションおよびレコードの使用 5-11

Page 150: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコレクション変数の宣言

例例例例 5-6 %TYPE およびおよびおよびおよび %ROWTYPE を使用したコレクション要素型の指定を使用したコレクション要素型の指定を使用したコレクション要素型の指定を使用したコレクション要素型の指定

要素型を指定するには、%TYPEを使用して変数またはデータベース列のデータ型を指定できます。また、%ROWTYPEを使用して、カーソルまたはデータベース表の行の型を指定できます。2 つの例を次に示します。

DECLARE-- Nested table type that can hold an arbitrary number of-- employee IDs. The element type is based on a column from-- the EMPLOYEES table. We do not need to know whether the-- ID is a number or a string. TYPE EmpList IS TABLE OF employees.employee_id%TYPE;

-- Array type that can hold information about 10 employees.-- The element type is a record that contains all the same-- fields as the EMPLOYEES table. TYPE Top_Salespeople IS VARRAY(10) OF employees%ROWTYPE;

-- Declare a cursor to select a subset of columns. CURSOR c1 IS SELECT first_name, last_name FROM employees;-- Array type that can hold a list of names. The element type-- is a record that contains the same fields as the cursor-- (that is, first_name and last_name). TYPE NameList IS VARRAY(20) OF c1%ROWTYPE;BEGIN NULL;END;/

例例例例 5-7 レコードとしてのレコードとしてのレコードとしてのレコードとしての VARRAY

次の例では、RECORD型を使用して、要素型を指定しています。

DECLARE TYPE GlossEntry IS RECORD ( term VARCHAR2(20), meaning VARCHAR2(200) ); TYPE Glossary IS VARRAY(250) OF GlossEntry;BEGIN NULL;END;/

5-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 151: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの初期化および参照

例例例例 5-8 コレクション要素のコレクション要素のコレクション要素のコレクション要素の NOT NULL 制約制約制約制約

NOT NULL制約は、要素型に対しても指定できます。

DECLARE TYPE EmpList IS TABLE OF employees.employee_id%TYPE NOT NULL; my_employees EmpList := EmpList(100, 150, 160, 200);BEGIN my_employees(3) := NULL; -- Assigning NULL raises an exceptionEND;/

コレクションの初期化および参照コレクションの初期化および参照コレクションの初期化および参照コレクションの初期化および参照ネストした表または VARRAY は、初期化されるまでは基本構造的に NULL(コレクションの要素ではなく、コレクション自体が NULL)です。ネストした表または VARRAY を初期化するには、コンストラクタを使用します。このコンストラクタは、コレクション型と同じ名前のシステム定義ファンクションです。このファンクションは、コレクションに渡される要素から、コレクションを構成します。

VARRAY やネストした表の変数に対しては、コンストラクタを明示的にコールする必要があります(第 3 のコレクションである結合配列は、コンストラクタを使用しません)。コンストラクタは、ファンクション・コールが許可されているところでコールできます。

例例例例 5-9 ネストした表のコンストラクタネストした表のコンストラクタネストした表のコンストラクタネストした表のコンストラクタ

次の例では、(ファンクションに類似し、コレクション型と同じ名前を持つ)コンストラクタを使用して、ネストした表を初期化しています。

DECLARE TYPE Colors IS TABLE OF VARCHAR2(16); rainbow Colors;BEGIN rainbow := Colors('Red','Orange','Yellow','Green','Blue','Indigo','Violet');END;/

ネストした表では 大サイズが宣言されていないため、コンストラクタには必要な数だけ要素を配置できます。

PL/SQL のコレクションおよびレコードの使用 5-13

Page 152: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの初期化および参照

例例例例 5-10 VARRAY のコンストラクタのコンストラクタのコンストラクタのコンストラクタ

この例では、(ファンクションに類似し、コレクション型と同じ名前を持つ)コンストラクタを使用して、VARRAY を初期化しています。

DECLARE-- In the varray, we put an upper limit on the number of elements. TYPE Colors IS VARRAY(10) OF VARCHAR2(16); rainbow Colors;BEGIN-- Since COLORS is declared as VARRAY(10), we can put up to 10-- elements in the constructor. rainbow := Colors('Red','Orange','Yellow','Green','Blue','Indigo','Violet');END;/

例例例例 5-11 NULL の要素を含むコレクションのコンストラクタの要素を含むコレクションのコンストラクタの要素を含むコレクションのコンストラクタの要素を含むコレクションのコンストラクタ

NULL の要素は、型の宣言で NOT NULL制約を指定しないかぎり、コンストラクタに渡すことができます。

DECLARE TYPE Colors IS TABLE OF VARCHAR2(20); my_colors Colors; TYPE ColorsNoNulls IS TABLE OF VARCHAR2(20) NOT NULL;BEGIN my_colors := Colors('Sienna',NULL,'Teal','Umber',NULL);-- If MY_COLORS was of type ColorsNoNulls, we could not include-- null values in the constructor.END;/

例例例例 5-12 コレクション宣言とコンストラクタの組合せコレクション宣言とコンストラクタの組合せコレクション宣言とコンストラクタの組合せコレクション宣言とコンストラクタの組合せ

コレクションは、そのコレクションの宣言で初期化できます。これはプログラミング上好ましい習慣です。

DECLARE TYPE Colors IS TABLE OF VARCHAR2(20); my_colors Colors := Colors('Brown','Gray','Beige');BEGIN NULL;END;/

5-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 153: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの初期化および参照

例例例例 5-13 空の空の空の空の VARRAY コンストラクタコンストラクタコンストラクタコンストラクタ

引数を指定しないでコンストラクタをコールすると、空(NULL ではない)のコレクションを受け取ります。

DECLARE TYPE Colors IS VARRAY(100) OF VARCHAR2(20); my_colors Colors;BEGIN IF my_colors IS NULL THEN dbms_output.put_line('Before initialization, the varray is null.');-- While the varray is null, we can't check its COUNT attribute.-- dbms_output.put_line('It has ' || my_colors.COUNT || ' elements.'); ELSE dbms_output.put_line('Before initialization, the varray is not null.'); END IF; my_colors := Colors(); -- initialize empty varray IF my_colors IS NULL THEN dbms_output.put_line('After initialization, the varray is null.'); ELSE dbms_output.put_line('After initialization, the varray is not null.'); dbms_output.put_line('It has ' || my_colors.COUNT || ' elements.'); END IF;END;/

この場合は、そのコレクションの EXTENDメソッドをコールして、後で要素を追加できます。

例例例例 5-14 SQL 文の中でのネストした表のコンストラクタ文の中でのネストした表のコンストラクタ文の中でのネストした表のコンストラクタ文の中でのネストした表のコンストラクタ

この例では、複数のスカラー値およびネストした表 CourseListを SOPHOMORES表に挿入しています。

BEGIN INSERT INTO sophomores VALUES (5035, 'Janet Alvarez', '122 Broad St', 'FT', CourseList('Econ 2010', 'Acct 3401', 'Mgmt 3100'));

例例例例 5-15 SQL 文の中での文の中での文の中での文の中での VARRAY コンストラクタコンストラクタコンストラクタコンストラクタ

この例では、行をデータベース表 DEPARTMENTに挿入しています。VARRAY コンストラクタ ProjectList()によって、列 PROJECTSの値が指定されます。

BEGIN INSERT INTO department VALUES(60, 'Security', 750400, ProjectList('New Badges', 'Track Computers', 'Check Exits'));

PL/SQL のコレクションおよびレコードの使用 5-15

Page 154: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの初期化および参照

コレクション要素の参照コレクション要素の参照コレクション要素の参照コレクション要素の参照要素への参照はいずれも、コレクション名と添字をカッコで囲んで指定します。この添字によって、処理の対象となる要素が決まります。要素を参照するには、次の構文を使用してその添字を指定します。

collection_name(subscript)

subscriptは、ほとんどの場合、結果が整数になる式か、または文字列キーで宣言した結合配列の場合は VARCHAR2です。

使用できる添字範囲は、次のとおりです。

� ネストした表の場合は、1 ~ 2**31 です。

� VARRAY の場合は、1 ~ size_limit(宣言に指定した制限)です。

� 数値キーの結合配列の場合は、-2**31 ~ 2**31 です。

� 文字列キーの結合配列の場合、キーの長さおよび使用可能な値の数は、型宣言に指定した VARCHAR2の長さ制限およびデータベース・キャラクタ・セットによって異なります。

例例例例 5-16 ネストした表の要素の添字による参照ネストした表の要素の添字による参照ネストした表の要素の添字による参照ネストした表の要素の添字による参照

この例は、ネストした表 NAMESの要素を参照する方法を示しています。

DECLARE TYPE Roster IS TABLE OF VARCHAR2(15); names Roster := Roster('J Hamil', 'D Caruso', 'R Singh');BEGIN FOR i IN names.FIRST .. names.LAST LOOP IF names(i) = 'J Hamil' THEN NULL; END IF; END LOOP;END;/

5-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 155: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの代入

例例例例 5-17 ネストした表の要素のパラメータとしての引渡しネストした表の要素のパラメータとしての引渡しネストした表の要素のパラメータとしての引渡しネストした表の要素のパラメータとしての引渡し

この例は、サブプログラム・コール中にコレクションの要素を参照できることを示しています。

DECLARE TYPE Roster IS TABLE OF VARCHAR2(15); names Roster := Roster('J Hamil', 'D Piro', 'R Singh'); i BINARY_INTEGER := 2;BEGIN verify_name(names(i)); -- call procedureEND;/

コレクションの代入コレクションの代入コレクションの代入コレクションの代入あるコレクションを、INSERT文、UPDATE文、FETCH文、SELECT文、代入文またはサブプログラム・コールよって、別のコレクションに代入できます。

次の構文を使用すると、式の値をコレクションの特定の要素に代入できます。

collection_name(subscript) := expression;

ここで、expressionは結果がコレクション型定義の要素に指定された型の値です。

SET、MULTISET UNION、MULTISET INTERSECT、MULTISET EXCEPTなどの演算子を使用して、ネストした表を代入文の一部として変換できます。

例例例例 5-18 コレクション代入のデータ型の互換性コレクション代入のデータ型の互換性コレクション代入のデータ型の互換性コレクション代入のデータ型の互換性

この例は、代入の操作では、コレクションに同じデータ型が必要であることを示しています。要素型が同じであることのみでは不十分です。

DECLARE TYPE last_name_typ IS VARRAY(3) OF VARCHAR2(64); TYPE surname_typ IS VARRAY(3) OF VARCHAR2(64);-- These first two variables have the same datatype. group1 last_name_typ := last_name_typ('Jones','Wong','Marceau'); group2 last_name_typ := last_name_typ('Klein','Patsos','Singh');-- This third variable has a similar declaration, but is not the same type. group3 surname_typ := surname_typ('Trevisi','Macleod','Marquez');BEGIN-- Allowed because they have the same datatype group1 := group2;-- Not allowed because they have different datatypes-- group3 := group2;END;/

PL/SQL のコレクションおよびレコードの使用 5-17

Page 156: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの代入

例例例例 5-19 NULL 値のネストした表への代入値のネストした表への代入値のネストした表への代入値のネストした表への代入

基本構造的に NULL のネストした表または VARRAY を、第 2 のネストした表またはVARRAY に代入する場合、第 2 のコレクションを再度初期化する必要があります。

DECLARE TYPE Colors IS TABLE OF VARCHAR2(64);-- This nested table has some values. crayons Colors := Colors('Silver','Gold');-- This nested table is not initialized ("atomically null"). empty_set Colors;BEGIN-- At first, the initialized variable is not null. if crayons IS NOT NULL THEN dbms_output.put_line('OK, at first crayons is not null.'); END IF;

-- Then we assign a null nested table to it. crayons := empty_set;

-- Now it is null. if crayons IS NULL THEN dbms_output.put_line('OK, now crayons has become null.'); END IF;

-- We must use another constructor to give it some values. crayons := Colors('Yellow','Green','Blue');END;/

同様に、値 NULLをコレクションに代入すると、コレクションは基本構造的に NULL になります。

例例例例 5-20 コレクション代入で予想される例外コレクション代入で予想される例外コレクション代入で予想される例外コレクション代入で予想される例外

値のコレクション要素への代入では、例外が発生する可能性があります。

� 添字が NULL であったり、正しいデータ型に変換することができない場合、PL/SQL は事前定義の例外 VALUE_ERRORを呼び出します。通常、添字は整数である必要があります。結合配列では、VARCHAR2の添字を使用するように宣言することもできます。

� 添字が初期化されていない要素を参照した場合、PL/SQL はSUBSCRIPT_BEYOND_COUNTを呼び出します。

� コレクションが基本構造的に NULL の場合、PL/SQL は COLLECTION_IS_NULLを呼び出します。

5-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 157: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの代入

DECLARE TYPE WordList IS TABLE OF VARCHAR2(5); words WordList;BEGIN /* Assume execution continues despite the raised exceptions. */-- Raises COLLECTION_IS_NULL. We haven't used a constructor yet.-- This exception applies to varrays and nested tables, but not to-- associative arrays which don't need a constructor. words(1) := 10;-- After using a constructor, we can assign values to the elements. words := WordList(10,20,30);-- Any expression that returns a VARCHAR2(5) is OK. words(1) := 'yes'; words(2) := words(1) || 'no';-- Raises VALUE_ERROR because the assigned value is too long. words(3) := 'longer than 5 characters';-- Raises VALUE_ERROR because the subscript of a nested table must-- be an integer. words('B') := 'dunno';-- Raises SUBSCRIPT_BEYOND_COUNT because we only made 3 elements-- in the constructor. To add new ones, we must call the EXTEND-- method first. words(4) := 'maybe';END;/

例例例例 5-21 集合演算子を使用したネストした表の代入集合演算子を使用したネストした表の代入集合演算子を使用したネストした表の代入集合演算子を使用したネストした表の代入

次の例では、ネストした表に適用可能な ANSI 規格のいくつかの演算子を示します。

DECLARE TYPE nested_typ IS TABLE OF NUMBER; nt1 nested_typ := nested_typ(1,2,3); nt2 nested_typ := nested_typ(3,2,1); nt3 nested_typ := nested_typ(2,3,1,3); nt4 nested_typ := nested_typ(1,2,4); answer nested_typ;

-- The results might be in a different order than you expect.-- (Remember, you should not rely on the order of elements in nested tables.) PROCEDURE print_nested_table(the_nt nested_typ) IS output VARCHAR2(128); BEGIN IF the_nt IS NULL THEN dbms_output.put_line('Results: <NULL>'); RETURN;

PL/SQL のコレクションおよびレコードの使用 5-19

Page 158: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの比較

END IF; IF the_nt.COUNT = 0 THEN dbms_output.put_line('Results: empty set'); RETURN; END IF; FOR i IN the_nt.FIRST .. the_nt.LAST LOOP output := output || the_nt(i) || ' '; END LOOP; dbms_output.put_line('Results: ' || output); END;BEGIN answer := nt1 MULTISET UNION nt4; -- (1,2,3,1,2,4) print_nested_table(answer); answer := nt1 MULTISET UNION nt3; -- (1,2,3,2,3,1,3) print_nested_table(answer); answer := nt1 MULTISET UNION DISTINCT nt3; -- (1,2,3) print_nested_table(answer);

answer := nt2 MULTISET INTERSECT nt3; -- (3,2,1) print_nested_table(answer); answer := nt2 MULTISET INTERSECT DISTINCT nt3; -- (3,2,1) print_nested_table(answer);

answer := SET(nt3); -- (2,3,1) print_nested_table(answer);

answer := nt3 MULTISET EXCEPT nt2; -- (3) print_nested_table(answer); answer := nt3 MULTISET EXCEPT DISTINCT nt2; -- () print_nested_table(answer);

END;/

コレクションの比較コレクションの比較コレクションの比較コレクションの比較コレクションが NULL かどうか、および 2 つのコレクションが同一かどうかをチェックできます。大きい、未満などの比較は実行できません。

この制限は、暗黙的な比較にも適用されます。たとえば、コレクションは DISTINCT、GROUP BYまたは ORDER BYリストには使用できません。

このような比較操作を行う場合は、2 つのコレクションが大きい、小さいなどを判断する手段をユーザーが任意に定義し、コレクションとその要素の調査結果を TRUE または FALSEの値で戻すような 1 つ以上のファンクションを記述する必要があります。

5-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 159: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの比較

集合演算子(CARDINALITY、MEMBER OF、IS A SET、IS EMPTYなど)を適用すると、1つのネストした表内または 2 つのネストした表の間で、特定の条件をチェックできます。

例例例例 5-22 コレクションがコレクションがコレクションがコレクションが NULL かどうかのチェックかどうかのチェックかどうかのチェックかどうかのチェック

ネストした表と VARRAY は、基本構造的に NULL の場合があるため、NULL かどうかをテストできます。

DECLARE TYPE Staff IS TABLE OF Employee; members Staff;BEGIN -- Condition yields TRUE because we haven't used a constructor. IF members IS NULL THEN ...END;

例例例例 5-23 2 つのコレクションの比較つのコレクションの比較つのコレクションの比較つのコレクションの比較

2 つのコレクションが等しいか等しくないかを比較できます。「大きい」または「未満」の比較は実行できないため、コレクションを順序付けすることはできません。

DECLARE TYPE Colors IS TABLE OF VARCHAR2(64); primaries Colors := Colors('Blue','Green','Red'); rgb Colors := Colors('Red','Green','Blue'); traffic_light Colors := Colors('Red','Green','Amber');BEGIN-- We can use = or !=, but not < or >.-- Notice that these 2 are equal even though the members are in different order. IF primaries = rgb THEN dbms_output.put_line('OK, PRIMARIES and RGB have the same members.'); END IF; IF rgb != traffic_light THEN dbms_output.put_line('OK, RGB and TRAFFIC_LIGHT have different members.'); END IF;END;/

PL/SQL のコレクションおよびレコードの使用 5-21

Page 160: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクションの比較

例例例例 5-24 集合演算子を使用したネストした表の比較集合演算子を使用したネストした表の比較集合演算子を使用したネストした表の比較集合演算子を使用したネストした表の比較

ANSI 規格の集合演算子を使用して、ネストした表の特定のプロパティをテストしたり、2つのネストした表を比較することができます。

DECLARE TYPE nested_typ IS TABLE OF NUMBER; nt1 nested_typ := nested_typ(1,2,3); nt2 nested_typ := nested_typ(3,2,1); nt3 nested_typ := nested_typ(2,3,1,3); nt4 nested_typ := nested_typ(1,2,4); answer BOOLEAN; howmany NUMBER; PROCEDURE testify(truth BOOLEAN DEFAULT NULL, quantity NUMBER DEFAULT NULL) IS BEGIN IF truth IS NOT NULL THEN dbms_output.put_line(CASE truth WHEN TRUE THEN 'True' WHEN FALSE THEN 'False' END); END IF; IF quantity IS NOT NULL THEN dbms_output.put_line(quantity); END IF; END;BEGIN answer := nt1 IN (nt2,nt3,nt4); -- true, nt1 matches nt2 testify(truth => answer); answer := nt1 SUBMULTISET OF nt3; -- true, all elements match testify(truth => answer); answer := nt1 NOT SUBMULTISET OF nt4; -- also true testify(truth => answer);

howmany := CARDINALITY(nt3); -- number of elements in nt3 testify(quantity => howmany); howmany := CARDINALITY(SET(nt3)); -- number of distinct elements testify(quantity => howmany);

answer := 4 MEMBER OF nt1; -- false, no element matches testify(truth => answer); answer := nt3 IS A SET; -- false, nt3 has duplicates testify(truth => answer); answer := nt3 IS NOT A SET; -- true, nt3 has duplicates testify(truth => answer); answer := nt1 IS EMPTY; -- false, nt1 has some members testify(truth => answer);END;/

5-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 161: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL 文での PL/SQL コレクションの使用

SQL 文での文での文での文での PL/SQL コレクションの使用コレクションの使用コレクションの使用コレクションの使用コレクションを使用すると、PL/SQL 内で複雑なデータ型を操作できます。添字を計算してメモリー内の特定の要素を処理し、SQL を使用してその結果をデータベース表に格納するようにプログラムを記述できます。

例例例例 5-25 PL/SQL のネストした表に対応したのネストした表に対応したのネストした表に対応したのネストした表に対応した SQL の型の作成の型の作成の型の作成の型の作成

SQL*Plus では、定義が PL/SQL のネストした表と VARRAY に対応した SQL の型を作成できます。

SQL> CREATE TYPE CourseList AS TABLE OF VARCHAR2(64);

次の SQL の型は、データベース表の列として使用できます。

SQL> CREATE TABLE department ( 2 name VARCHAR2(20), 3 director VARCHAR2(20), 4 office VARCHAR2(20), 5 courses CourseList) 6 NESTED TABLE courses STORE AS courses_tab;

列 COURSES内の各項目は、指定された学部(department)が提供するコースを格納するネストした表です。データベース表にネストした表の列がある場合は常に、NESTED TABLE句が必要です。この句は、ネストした表を識別し、システム生成された記憶域表に名前を指定します。Oracle はネストした表のデータをこの記憶域表に格納します。

例例例例 5-26 ネストした表のデータベース表への挿入ネストした表のデータベース表への挿入ネストした表のデータベース表への挿入ネストした表のデータベース表への挿入

データベース表に、データを移入できます。表のコンストラクタによって、単一の列COURSESに入るすべての値が指定されます。

BEGIN INSERT INTO department VALUES('English', 'Lynn Saunders', 'Breakstone Hall 205', CourseList('Expository Writing', 'Film and Literature', 'Modern Science Fiction', 'Discursive Writing', 'Modern English Grammar', 'Introduction to Shakespeare', 'Modern Drama', 'The Short Story', 'The American Novel'));END;

PL/SQL のコレクションおよびレコードの使用 5-23

Page 162: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL 文での PL/SQL コレクションの使用

例例例例 5-27 INSERT、、、、UPDATE、、、、DELETE およびおよびおよびおよび SELECT 文での文での文での文での PL/SQL のネストした表の使用のネストした表の使用のネストした表の使用のネストした表の使用

英語学部が提供するすべてのコースを、PL/SQL のネストした表に取り出すことができます。

CREATE TYPE ColorList AS TABLE OF VARCHAR2(64);/CREATE TABLE flowers (name VARCHAR2(20), colors ColorList) NESTED TABLE colors STORE AS colors_tab;

BEGIN INSERT INTO flowers VALUES('Rose', ColorList('Red','Yellow','White')); INSERT INTO flowers VALUES('Tulip', ColorList('Red','White','Yellow', 'Blue')); INSERT INTO flowers VALUES('Iris', ColorList('White','Purple')); COMMIT;END;/

DECLARE-- This type declaration is not needed, because PL/SQL can see the SQL type.-- TYPE ColorList IS TABLE OF VARCHAR2(64);-- Declare a variable that can hold a set of colors. my_colors ColorList;-- Declare a record that can hold a row from the table.-- One of the record fields is a set of colors. my_flower flowers%ROWTYPE; new_colors ColorList;BEGIN-- Look up a name and query just the associated colors. SELECT colors INTO my_colors FROM flowers WHERE name = 'Rose'; FOR i IN my_colors.FIRST .. my_colors.LAST LOOP dbms_output.put_line('Rose color = ' || my_colors(i)); END LOOP;

-- Look up a name and query the entire row. SELECT * INTO my_flower FROM flowers WHERE name = 'Iris';-- Now COLORS is a field in a record, so we access it with dot notation. FOR i IN my_flower.colors.FIRST .. my_flower.colors.LAST LOOP-- Because we have all the table columns in the record, we can refer to NAME also. dbms_output.put_line(my_flower.name || ' color = ' || my_flower.colors(i)); END LOOP;

-- We can replace a set of colors by making a new collection and using it-- in an UPDATE statement. new_colors := ColorList('Red','Yellow','White','Pink'); UPDATE flowers SET colors = new_colors WHERE name = 'Rose';

5-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 163: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL 文での PL/SQL コレクションの使用

-- Or we can modify the original collection and use it in the UPDATE.-- We'll add a new final element and fill in a value. my_flower.colors.EXTEND(1); my_flower.colors(my_flower.colors.COUNT) := 'Yellow'; UPDATE flowers SET colors = my_flower.colors WHERE name = my_flower.name;

-- We can even treat the nested table column like a real table and-- insert, update, or delete elements.-- The TABLE operator makes the statement apply to the nested table produced by the subquery.

INSERT INTO TABLE(SELECT colors FROM flowers WHERE name = 'Rose') VALUES('Black'); DELETE FROM TABLE(SELECT colors FROM flowers WHERE name = 'Rose') WHERE column_value = 'Yellow'; UPDATE TABLE(SELECT colors FROM flowers WHERE name = 'Iris') SET column_value = 'Indigo' WHERE column_value = 'Purple';

COMMIT;END;/

DROP TABLE flowers;DROP TYPE ColorList;

PL/SQL 内では、ネストした表の要素をループし、TRIMや EXTENDなどのメソッドを使用し、要素の一部またはすべてを更新することによって、ネストした表を操作できます。その後、更新した表をデータベースに再度格納できます。

例例例例 5-28 データベース表でのネストした表の更新データベース表でのネストした表の更新データベース表でのネストした表の更新データベース表でのネストした表の更新

英語学部が提供するコースのリストは、改訂することができます。

DECLARE new_courses CourseList := CourseList('Expository Writing', 'Film and Literature', 'Discursive Writing', 'Modern English Grammar', 'Realism and Naturalism', 'Introduction to Shakespeare', 'Modern Drama', 'The Short Story', 'The American Novel', '20th-Century Poetry', 'Advanced Workshop in Poetry');

PL/SQL のコレクションおよびレコードの使用 5-25

Page 164: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL 文での PL/SQL コレクションの使用

BEGIN UPDATE department SET courses = new_courses WHERE name = 'English';END;

INSERT、、、、UPDATE およびおよびおよびおよび SELECT 文での文での文での文での PL/SQL のののの VARRAY の使用の使用の使用の使用次の例は、PL/SQL 変数と SQL 表の間で VARRAY を送信する方法を示しています。VARRAY を含む表の行を挿入したり、行を更新して VARRAY を置換したり、PL/SQL 変数に送信する VARRAY を選択することができます。SQL を使用して、VARRAY の個々の要素を直接更新または削除することはできません。表から VARRAY を選択し、PL/SQL 内で変更してから、表を更新してその新しい VARRAY を含める必要があります。

-- By using a varray, we put an upper limit on the number of elements-- and ensure they always come back in the same order.CREATE TYPE RainbowTyp AS VARRAY(7) OF VARCHAR2(64);/

CREATE TABLE rainbows (language VARCHAR2(64), colors RainbowTyp);

BEGIN INSERT INTO rainbows VALUES('English', RainbowTyp('Red','Orange','Yellow','Green','Blue','Indigo','Violet')); INSERT INTO rainbows VALUES('Francais', RainbowTyp('Rouge','Orange','Jaune','Vert','Bleu','Indigo','Violet')); COMMIT;END;/

DECLARE new_colors RainbowTyp := RainbowTyp('Crimson','Orange','Amber','Forest','Azure','Indigo','Violet'); some_colors RainbowTyp;BEGIN UPDATE rainbows SET colors = new_colors WHERE language = 'English'; COMMIT; SELECT colors INTO some_colors FROM rainbows WHERE language = 'Francais'; FOR i IN some_colors.FIRST .. some_colors.LAST LOOP dbms_output.put_line('Color = ' || some_colors(i)); END LOOP;END;/

DROP TABLE rainbows;DROP TYPE RainbowTyp;

5-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 165: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

マルチレベル・コレクションの使用

SQL での個々のコレクション要素の操作での個々のコレクション要素の操作での個々のコレクション要素の操作での個々のコレクション要素の操作デフォルトの SQL 操作では、個々の要素ではなく、コレクション全体が格納および取得されます。SQL で、コレクションの個々の要素を操作するには、TABLE演算子を使用します。TABLE演算子は、副問合せを使用して VARRAY またはネストした表を抽出します。その結果、INSERT文、UPDATE文または DELETE文が、トップレベルの表ではなく、ネストした表に適用されます。

例例例例 5-29 PL/SQL のネストした表でののネストした表でののネストした表でののネストした表での INSERT、、、、UPDATE およびおよびおよびおよび DELETE 操作の実行操作の実行操作の実行操作の実行

PL/SQL のネストした表での DML 操作には、TABLE演算子と CAST演算子を使用します。この方法によって、ネストした表をデータベースに実際に格納せずに、SQL 表記法を使用してネストした表で集合演算を実行できます。

CASTのオペランドは、PL/SQL コレクション変数と SQL コレクション型(CREATE TYPE文で作成)です。CASTによって、PL/SQL コレクションが SQL の型に変換されます。

DECLARE revised CourseList := CourseList(Course(1002, 'Expository Writing', 3), Course(2020, 'Film and Literature', 4), Course(4210, '20th-Century Poetry', 4), Course(4725, 'Advanced Workshop in Poetry', 5)); num_changed INTEGER;BEGIN SELECT COUNT(*) INTO num_changed FROM TABLE(CAST(revised AS CourseList)) new, TABLE(SELECT courses FROM department WHERE name = 'English') AS old WHERE new.course_no = old.course_no AND (new.title != old.title OR new.credits != old.credits); dbms_output.put_line(num_changed);END;

マルチレベル・コレクションの使用マルチレベル・コレクションの使用マルチレベル・コレクションの使用マルチレベル・コレクションの使用スカラー型やオブジェクト型のコレクションの他に、コレクションを要素に持つコレクションも作成できます。たとえば、VARRAY のネストした表、VARRAY の VARRAY、ネストした表の VARRAY などを作成できます。

ネストした表のネストした表を SQL の列として作成する場合は、CREATE TABLE文の構文をチェックして、記憶表の定義方法を確認します。

マルチレベル・コレクションの構文と可能性を示す例を次に示します。

PL/SQL のコレクションおよびレコードの使用 5-27

Page 166: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

マルチレベル・コレクションの使用

例例例例 5-30 マルチレベルマルチレベルマルチレベルマルチレベル VARRAY

declare type t1 is varray(10) of integer; type nt1 is varray(10) of t1; -- multilevel varray type va t1 := t1(2,3,5);-- initialize multilevel varray nva nt1 := nt1(va, t1(55,6,73), t1(2,4), va); i integer; va1 t1;begin -- multilevel access i := nva(2)(3); -- i will get value 73 dbms_output.put_line('I = ' || i); -- add a new varray element to nva nva.extend;

-- replace inner varray elements nva(5) := t1(56, 32); nva(4) := t1(45,43,67,43345);-- replace an inner integer element nva(4)(4) := 1; -- replaces 43345 with 1-- add a new element to the 4th varray element-- and store integer 89 into it. nva(4).extend; nva(4)(5) := 89;end;/

例例例例 5-31 マルチレベルのネストした表マルチレベルのネストした表マルチレベルのネストした表マルチレベルのネストした表

declare type tb1 is table of varchar2(20); type ntb1 is table of tb1; -- table of table elements type tv1 is varray(10) of integer; type ntb2 is table of tv1; -- table of varray elements

vtb1 tb1 := tb1('one', 'three'); vntb1 ntb1 := ntb1(vtb1); vntb2 ntb2 := ntb2(tv1(3,5), tv1(5,7,3)); -- table of varray elementsbegin vntb1.extend; vntb1(2) := vntb1(1);-- delete the first element in vntb1 vntb1.delete(1);-- delete the first string from the second table in the nested table vntb1(2).delete(1);

5-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 167: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

マルチレベル・コレクションの使用

end;/

例例例例 5-32 マルチレベルの結合配列マルチレベルの結合配列マルチレベルの結合配列マルチレベルの結合配列

declare type tb1 is table of integer index by binary_integer;-- the following is index-by table of index-by tables type ntb1 is table of tb1 index by binary_integer; type va1 is varray(10) of varchar2(20);-- the following is index-by table of varray elements type ntb2 is table of va1 index by binary_integer;

v1 va1 := va1('hello', 'world'); v2 ntb1; v3 ntb2; v4 tb1; v5 tb1; -- empty tablebegin v4(1) := 34; v4(2) := 46456; v4(456) := 343; v2(23) := v4; v3(34) := va1(33, 456, 656, 343);-- assign an empty table to v2(35) and try again v2(35) := v5; v2(35)(2) := 78; -- it works nowend;/

例例例例 5-33 マルチレベル・コレクションおよびバルクマルチレベル・コレクションおよびバルクマルチレベル・コレクションおよびバルクマルチレベル・コレクションおよびバルク SQL

create type t1 is varray(10) of integer;/create table tab1 (c1 t1);

insert into tab1 values (t1(2,3,5));insert into tab1 values (t1(9345, 5634, 432453));

declare type t2 is table of t1; v2 t2;begin select c1 BULK COLLECT INTO v2 from tab1; dbms_output.put_line(v2.count); -- prints 2

PL/SQL のコレクションおよびレコードの使用 5-29

Page 168: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

end;/

drop table tab1;drop type t1;

コレクション・メソッドの使用コレクション・メソッドの使用コレクション・メソッドの使用コレクション・メソッドの使用次に示すコレクション・メソッドを使用すると、コレクションの使用およびアプリケーションの維持が簡単になります。

EXISTSCOUNTLIMITFIRST および LASTPRIOR および NEXTEXTENDTRIMDELETE

コレクション・メソッドコレクション・メソッドコレクション・メソッドコレクション・メソッドとは、コレクションに対する操作を実行するための、ドット表記法を使用してコールされる組込みファンクションまたはプロシージャです。

コレクション・メソッドは、SQL 文からはコールできません。

EXTENDと TRIMは、結合配列で使用できません。

EXISTS、COUNT、LIMIT、FIRST、LAST、PRIORおよび NEXTは、ファンクションです。EXTEND、TRIMおよび DELETEはプロシージャです。

EXISTS、PRIOR、NEXT、TRIM、EXTENDおよび DELETEは、コレクションの添字に対応するパラメータを取ります。通常、この添字は整数ですが、結合配列の場合は文字列も使用できます。

基本構造的に NULL であるコレクションに適用されるのは EXISTSのみです。それ以外のメソッドをそのようなコレクションに適用すると、PL/SQL は COLLECTION_IS_NULLを呼び出します。

5-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 169: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

コレクション要素の存在のチェック(コレクション要素の存在のチェック(コレクション要素の存在のチェック(コレクション要素の存在のチェック(EXISTS メソッド)メソッド)メソッド)メソッド)EXISTS(n)は、コレクションに n番目の要素が存在する場合に TRUEを戻します。それ以外の場合、EXISTS(n)は FALSEを戻します。EXISTSと DELETEを組み合せると、疎であるネストした表を操作できます。また、EXISTSを使用すると、存在しない要素を参照したことによる例外の発生を回避できます。範囲外の添字を渡した場合、EXISTSはSUBSCRIPT_OUTSIDE_LIMITを呼び出さずに、FALSEを戻します。

DECLARE TYPE NumList IS TABLE OF INTEGER; n NumList := NumList(1,3,5,7);BEGIN n.DELETE(2); -- Delete the second element IF n.EXISTS(1) THEN dbms_output.put_line('OK, element #1 exists.'); END IF; IF n.EXISTS(2) = FALSE THEN dbms_output.put_line('OK, element #2 has been deleted.'); END IF; IF n.EXISTS(99) = FALSE THEN dbms_output.put_line('OK, element #99 does not exist at all.'); END IF;END;/

コレクション内の要素数のカウント(コレクション内の要素数のカウント(コレクション内の要素数のカウント(コレクション内の要素数のカウント(COUNT メソッド)メソッド)メソッド)メソッド)COUNTは、コレクションに現在含まれている要素の数を戻します。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(2,4,6,8); -- Collection starts with 4 elements.BEGIN dbms_output.put_line('There are ' || n.COUNT || ' elements in N.'); n.EXTEND(3); -- Add 3 new elements at the end. dbms_output.put_line('Now there are ' || n.COUNT || ' elements in N.'); n := NumList(86,99); -- Assign a completely new value with 2 elements. dbms_output.put_line('Now there are ' || n.COUNT || ' elements in N.'); n.TRIM(2); -- Remove the last 2 elements, leaving none. dbms_output.put_line('Now there are ' || n.COUNT || ' elements in N.');END;/

コレクションの現在のサイズは不明の場合があるため、そのような場合に COUNTが役立ちます。たとえば、Oracle データの列をフェッチしてネストした表に入れることができます。この場合、結果セットのサイズに応じて要素の数を決めます。

PL/SQL のコレクションおよびレコードの使用 5-31

Page 170: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

VARRAY の場合、COUNTは常に LASTと同じです。EXTENDおよび TRIMメソッドを使用して、VARRAY のサイズを増減できます。この場合、COUNT値の上限は LIMITメソッドで指定した値になります。

ネストした表の場合、COUNTは通常、LASTと同じです。ただし、ネストした表の途中から要素を削除すると、COUNTは LASTより小さくなります。要素を総計するときに、COUNTは削除された要素を無視します。

コレクションの最大サイズのチェック(コレクションの最大サイズのチェック(コレクションの最大サイズのチェック(コレクションの最大サイズのチェック(LIMIT メソッド)メソッド)メソッド)メソッド)大サイズが指定されていないネストした表や結合配列の場合、LIMITは NULLを戻しま

す。VARRAY の場合、LIMITは VARRAY に入れることのできる要素の 大数を戻します(この 大数は型定義で指定し、TRIMメソッドや EXTENDメソッドを使用して後で変更できます)。たとえば、VARRAY PROJECTSの 大要素数が 25 個である場合、次の IF条件はTRUE です。

DECLARE TYPE Colors IS VARRAY(7) OF VARCHAR2(64); c Colors := Colors('Gold','Silver');BEGIN dbms_output.put_line('C has ' || c.COUNT || ' elements now.'); dbms_output.put_line('C''s type can hold a maximum of ' || c.LIMIT || ' elements.'); dbms_output.put_line('The maximum number you can use with C.EXTEND() is ' || (c.LIMIT - c.COUNT));END;/

最初または最後のコレクション要素の検索(最初または最後のコレクション要素の検索(最初または最後のコレクション要素の検索(最初または最後のコレクション要素の検索(FIRST メソッドとメソッドとメソッドとメソッドと LAST メソッド)メソッド)メソッド)メソッド)FIRSTと LASTは、それぞれ整数の添字を使用しているコレクションの 初と 後( 小と大)の索引番号を戻します。

キー値が VARCHAR2の結合配列の場合は、 小および 大のキー値が戻ります。デフォルトでは、文字列内の文字のバイナリ値に基づいて順序付けが行われます。NLS_COMP初期化パラメータが ANSIに設定されている場合、順序付けは NLS_SORT初期化パラメータで指定したロケール固有のソート順に基づきます。

コレクションが空の場合、FIRSTと LASTは NULLを戻します。

コレクションに含まれる要素の数が 1 つのみの場合、FIRSTと LASTは同じ索引値を戻します。

5-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 171: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

次の例は、FIRSTおよび LASTを使用して、添字が連続しているコレクションの要素に対して反復処理を実行する方法を示しています。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(1,3,5,7); counter INTEGER;BEGIN dbms_output.put_line('N''s first subscript is ' || n.FIRST); dbms_output.put_line('N''s last subscript is ' || n.LAST);

-- When the subscripts are consecutive starting at 1, it's simple to loop through them. FOR i IN n.FIRST .. n.LAST LOOP dbms_output.put_line('Element #' || i || ' = ' || n(i)); END LOOP;

n.DELETE(2); -- Delete second element.-- When the subscripts have gaps or the collection might be uninitialized,-- the loop logic is more extensive. We start at the first element, and-- keep looking for the next element until there are no more. IF n IS NOT NULL THEN counter := n.FIRST; WHILE counter IS NOT NULL LOOP dbms_output.put_line('Element #' || counter || ' = ' || n(counter)); counter := n.NEXT(counter); END LOOP; ELSE dbms_output.put_line('N is null, nothing to do.'); END IF;END;/

VARRAY の場合、FIRSTは常に 1 を戻し、LASTは常に COUNTと同じです。

ネストした表の場合、通常は FIRSTは 1 を戻し、LASTは COUNTと同じです。ただし、ネストした表の先頭から要素を削除すると、FIRSTは 1 より大きい数値を戻します。また、ネストした表の途中から要素を削除すると、LASTは COUNTより大きくなります。

要素をスキャンするときに、FIRSTおよび LASTは削除された要素を無視します。

PL/SQL のコレクションおよびレコードの使用 5-33

Page 172: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

コレクションの各要素のループ(コレクションの各要素のループ(コレクションの各要素のループ(コレクションの各要素のループ(PRIOR メソッドとメソッドとメソッドとメソッドと NEXT メソッド)メソッド)メソッド)メソッド)PRIOR(n) は、コレクションの索引 nの前の索引番号を戻します。NEXT(n)は、索引 nの後の索引番号を戻します。nの前の番号がない場合、PRIOR(n)は NULLを戻します。nの後の番号がない場合、NEXT(n)は NULLを戻します。

キーが VARCHAR2型の結合配列の場合は、これらのメソッドは適切なキー値を戻します。NLS_COMP初期化パラメータが ANSIに設定されていないかぎり、順序付けは文字列内の文字のバイナリ値に従います。この場合、ANSI の場合の順序付けは、NLS_SORT初期化パラメータで指定したロケール固有のソート順に従います。

これらのメソッドは、添字の値の固定セットを使用したループに比べて高い信頼性があります。これは、ループ中にコレクションの要素が挿入または削除される可能性があるためです。特に結合配列の場合、添字は連続した順序ではないため、添字の順序が(1、2、4、8、16)や('A'、'E'、'I'、'O'、'U')となっている可能性があります。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(1966,1971,1984,1989,1999);BEGIN dbms_output.put_line('The element after #2 is #' || n.NEXT(2)); dbms_output.put_line('The element before #2 is #' || n.PRIOR(2)); n.DELETE(3); -- Delete an element to show how NEXT can handle gaps. dbms_output.put_line('Now the element after #2 is #' || n.NEXT(2)); IF n.PRIOR(n.FIRST) IS NULL THEN dbms_output.put_line('Can''t get PRIOR of the first element or NEXT of the last.'); END IF;END;/

PRIORまたは NEXTを使用すると、任意の添字列を索引とするコレクション内を移動できます。次の例では、NEXTを使用して、いくつかの要素が削除されたネストした表内を移動しています。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(1,3,5,7); counter INTEGER;BEGIN n.DELETE(2); -- Delete second element.-- When the subscripts have gaps, the loop logic is more extensive. We start at the-- first element, and keep looking for the next element until there are no more. counter := n.FIRST; WHILE counter IS NOT NULL LOOP dbms_output.put_line('Counting up: Element #' || counter || ' = ' || n(counter));

5-34 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 173: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

counter := n.NEXT(counter); END LOOP;

-- Run the same loop in reverse order. counter := n.LAST; WHILE counter IS NOT NULL LOOP dbms_output.put_line('Counting down: Element #' || counter || ' = ' || n(counter)); counter := n.PRIOR(counter); END LOOP;END;/

要素間を横断するときに、PRIORおよび NEXTは削除された要素をスキップします。

コレクションのサイズの拡大(コレクションのサイズの拡大(コレクションのサイズの拡大(コレクションのサイズの拡大(EXTEND メソッド)メソッド)メソッド)メソッド)ネストした表または VARRAY のサイズを大きくするには、EXTENDを使用します。

索引付き表で EXTENDを使用することはできません。

このプロシージャには次の 3 つの形式があります。

� EXTENDは、コレクションに 1 つの NULL 要素を追加します。

� EXTEND(n)は、コレクションに n個の NULL 要素を追加します。

� EXTEND(n,i)は、コレクションに i番目の要素のコピーを n個追加します。

EXTENDを使用して、初期化されていないコレクションに要素を追加することはできません。

NOT NULL制約を TABLEまたは VARRAY型に指定した場合、EXTENDの 初の 2 つの形式はその型のコレクションに適用できません。

EXTENDは、削除された要素を含むコレクションの内部サイズに対して操作します。EXTENDは削除された要素を見つけると、それらの要素を数に含めます。PL/SQL は削除された要素のプレースホルダを保持するため、新しい値を代入して要素を再作成できます。

DECLARE TYPE NumList IS TABLE OF INTEGER; n NumList := NumList(2,4,6,8); x NumList := NumList(1,3); PROCEDURE print_numlist(the_list NumList) IS output VARCHAR2(128); BEGIN FOR i IN the_list.FIRST .. the_list.LAST LOOP output := output || NVL(TO_CHAR(the_list(i)),'NULL') || ' ';

PL/SQL のコレクションおよびレコードの使用 5-35

Page 174: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

END LOOP; dbms_output.put_line(output); END;BEGIN dbms_output.put_line('At first, N has ' || n.COUNT || ' elements.'); n.EXTEND(5); -- Add 5 elements at the end. dbms_output.put_line('Now N has ' || n.COUNT || ' elements.');-- Elements 5, 6, 7, 8, and 9 are all NULL. print_numlist(n);

dbms_output.put_line('At first, X has ' || x.COUNT || ' elements.'); x.EXTEND(4,2); -- Add 4 elements at the end. dbms_output.put_line('Now X has ' || x.COUNT || ' elements.');-- Elements 3, 4, 5, and 6 are copies of element #2. print_numlist(x);END;/

削除された要素を含めると、ネストした表の内部サイズは、COUNTと LASTが戻す値とは異なります。たとえば、ネストした表を 5 つの要素で初期化してから、要素 2 と要素 5 を削除した場合、内部サイズは 5 で、COUNTは 3 を戻し、LASTは 4 を戻します。削除されたすべての要素は、その位置に関係なく同様に処理されます。

コレクションのサイズの縮小(コレクションのサイズの縮小(コレクションのサイズの縮小(コレクションのサイズの縮小(TRIM メソッド)メソッド)メソッド)メソッド)このプロシージャには次の 2 つの形式があります。

� TRIMは、コレクションの末尾から 1 つの要素を削除します。

� TRIM(n)は、コレクションの末尾から n個の要素を削除します。

たとえば、次の文では、ネストした表の coursesから 後の 3 つの要素を削除します。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(1,2,3,5,7,11); PROCEDURE print_numlist(the_list NumList) IS output VARCHAR2(128); BEGIN IF n.COUNT = 0 THEN dbms_output.put_line('No elements in collection.'); ELSE FOR i IN the_list.FIRST .. the_list.LAST LOOP output := output || NVL(TO_CHAR(the_list(i)),'NULL') || ' '; END LOOP; dbms_output.put_line(output); END IF;

5-36 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 175: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

END;BEGIN print_numlist(n); n.TRIM(2); -- Remove last 2 elements. print_numlist(n); n.TRIM; -- Remove last element. print_numlist(n); n.TRIM(n.COUNT); -- Remove all remaining elements. print_numlist(n);

-- If too many elements are specified, TRIM raises the exception SUBSCRIPT_BEYOND_COUNT. BEGIN n := NumList(1,2,3); n.TRIM(100); EXCEPTION WHEN SUBSCRIPT_BEYOND_COUNT THEN dbms_output.put_line('I guess there weren''t 100 elements that could be trimmed.'); END;

-- When elements are removed by DELETE, placeholders are left behind. TRIM counts these-- placeholders as it removes elements from the end.

n := NumList(1,2,3,4); n.DELETE(3); -- delete element 3-- At this point, n contains elements (1,2,4).-- TRIMming the last 2 elements removes the 4 and the placeholder, not 4 and 2. n.TRIM(2); print_numlist(n);END;/END;/

nが大きすぎる場合、TRIM(n)は SUBSCRIPT_BEYOND_COUNTを呼び出します。

TRIMは、コレクションの内部サイズに対して操作します。TRIMは削除された要素を見つけると、それらの要素を数に含めます。次の例を考えます。

DECLARE TYPE CourseList IS TABLE OF VARCHAR2(10); courses CourseList;BEGIN courses := CourseList('Biol 4412', 'Psyc 3112', 'Anth 3001'); courses.DELETE(courses.LAST); -- delete element 3 /* At this point, COUNT equals 2, the number of valid

PL/SQL のコレクションおよびレコードの使用 5-37

Page 176: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッドの使用

elements remaining. So, you might expect the next statement to empty the nested table by trimming elements 1 and 2. Instead, it trims valid element 2 and deleted element 3 because TRIM includes deleted elements in its tally. */ courses.TRIM(courses.COUNT); dbms_output.put_line(courses(1)); -- prints 'Biol 4412'END;/

一般に、TRIMと DELETEの間の相互作用には依存しないでください。ネストした表は、固定サイズの配列のように扱って DELETEのみを使用するか、またはスタックのように扱ってTRIMと EXTENDのみを使用することをお薦めします。

PL/SQL は切り捨てられた(TRIM)要素のプレースホルダを保持しないため、切り捨てられた要素に新しい値を代入するのみではその要素を置き換えることができません。

コレクション要素の削除(コレクション要素の削除(コレクション要素の削除(コレクション要素の削除(DELETE メソッド)メソッド)メソッド)メソッド)このプロシージャには次の様々な形式があります。

� DELETEは、コレクションからすべての要素を削除します。

� DELETE(n)は、数値キーの結合配列またはネストした表から n番目の要素を削除します。結合配列のキーが文字列の場合は、そのキー値に対応する要素が削除されます。nが NULL である場合、DELETE(n)は何も実行しません。

� DELETE(m,n)は、結合配列またはネストした表から m~ nの範囲のすべての要素を削除します。mが nより大きい場合、または mか nが NULL である場合、DELETE(m,n)は何も実行しません。

次に例を示します。

DECLARE TYPE NumList IS TABLE OF NUMBER; n NumList := NumList(10,20,30,40,50,60,70,80,90,100); TYPE NickList IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(32); nicknames NickList;BEGIN n.DELETE(2); -- deletes element 2 n.DELETE(3,6); -- deletes elements 3 through 6 n.DELETE(7,7); -- deletes element 7 n.DELETE(6,3); -- does nothing since 6 > 3

n.DELETE; -- deletes all elements

nicknames('Bob') := 'Robert'; nicknames('Buffy') := 'Esmerelda'; nicknames('Chip') := 'Charles';

5-38 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 177: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション例外の回避

nicknames('Dan') := 'Daniel'; nicknames('Fluffy') := 'Ernestina'; nicknames('Rob') := 'Robert';

nicknames.DELETE('Chip'); -- deletes element denoted by this key nicknames.DELETE('Buffy','Fluffy'); -- deletes elements with keys in this alphabetic rangeEND;/

VARRAY の添字は常に連続しているため、(TRIMメソッドを使用して)末尾の要素を削除することを除き、個々の要素は削除できません。

削除対象の要素が存在しない場合でも、DELETEは単にその要素をスキップするため、例外は呼び出されません。PL/SQL は削除された要素のプレースホルダを保持するため、削除された要素に新しい値を代入して、その要素を置き換えることができます。

DELETEを使用すると、疎であるネストした表を維持できます。疎であるネストした表は、その他のネストした表と同様に、データベース内に格納できます。

ネストした表に割り当てられるメモリーの量は、動的に増減します。要素を削除すると、メモリーはページ単位で解放されます。表全体を削除した場合は、すべてのメモリーが解放されます。

コレクション・パラメータへのメソッドの適用コレクション・パラメータへのメソッドの適用コレクション・パラメータへのメソッドの適用コレクション・パラメータへのメソッドの適用サブプログラム内で、コレクション・パラメータは引数のプロパティがバインドされていることを前提にしています。組込みコレクション・メソッド(FIRST、LAST、COUNTなど)をそのようなパラメータに適用できます。コレクション・パラメータを取って要素に反復処理を実行したり、要素を追加または削除する、汎用目的のサブプログラムを作成できます。

注意注意注意注意 : VARRAY パラメータの場合、パラメータ・モードに関係なく、LIMITの値は常にパラメータの型定義から導出されます。

コレクション例外の回避コレクション例外の回避コレクション例外の回避コレクション例外の回避ほとんどの場合、存在しないコレクション要素を参照すると、PL/SQL は事前定義された例外を呼び出します。次の例を考えます。

DECLARE TYPE NumList IS TABLE OF NUMBER; nums NumList; -- atomically nullBEGIN /* Assume execution continues despite the raised exceptions. */ nums(1) := 1; -- raises COLLECTION_IS_NULL (1) nums := NumList(1,2); -- initialize nested table nums(NULL) := 3; -- raises VALUE_ERROR (2)

PL/SQL のコレクションおよびレコードの使用 5-39

Page 178: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション例外の回避

nums(0) := 3; -- raises SUBSCRIPT_OUTSIDE_LIMIT (3) nums(3) := 3; -- raises SUBSCRIPT_BEYOND_COUNT (4) nums.DELETE(1); -- delete element 1 IF nums(1) = 1 THEN NULL; END IF; -- raises NO_DATA_FOUND (5)END;/

初のケースでは、ネストした表は基本構造的に NULL です。2 番目のケースでは、添字がNULL です。3 番目のケースでは、添字は有効範囲外です。4 番目のケースでは、添字は表の要素数を超えています。5 番目のケースでは、添字は削除された要素を指定しています。

次のリストは、指定された例外が呼び出される場合を示しています。

場合によっては、例外を呼び出さずに、無効な添字をメソッドに渡すことができます。たとえば、NULL 添字をプロシージャ DELETEに渡しても、何も実行されません。削除された要素に値を代入すると、NO_DATA_FOUNDを呼び出さずにその要素を置き換えることができます。

DECLARE TYPE NumList IS TABLE OF NUMBER; nums NumList := NumList(10,20,30); -- initialize tableBEGIN nums.DELETE(-1); -- does not raise SUBSCRIPT_OUTSIDE_LIMIT nums.DELETE(3); -- delete 3rd element dbms_output.put_line(nums.COUNT); -- prints 2 nums(3) := 30; -- allowed; does not raise NO_DATA_FOUND dbms_output.put_line(nums.COUNT); -- prints 3END;/

コレクションに関する例外コレクションに関する例外コレクションに関する例外コレクションに関する例外 呼び出される場合呼び出される場合呼び出される場合呼び出される場合

COLLECTION_IS_NULL 基本構造的に NULL のコレクションに対して操作を試みた

場合。

NO_DATA_FOUND 添字で、削除されている要素や結合配列の存在していない要素が指定された場合。

SUBSCRIPT_BEYOND_COUNT 添字がコレクションの中の要素数を超えている場合。

SUBSCRIPT_OUTSIDE_LIMIT 添字が有効範囲外である場合。

VALUE_ERROR 添字が NULL か、またはキーの型に変換できない場合。こ

の例外は、キーが PLS_INTEGERの範囲として定義され、添

字がこの範囲外の場合に発生する可能性があります。

5-40 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 179: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードの定義と宣言

パッケージ・コレクション型とローカル・コレクション型には互換性がありません。たとえば、次のパッケージ・プロシージャをコールするとします。

CREATE PACKAGE pkg AS TYPE NumList IS TABLE OF NUMBER; PROCEDURE print_numlist (nums NumList);END pkg;/

DECLARE TYPE NumList IS TABLE OF NUMBER; n1 pkg.NumList := pkg.NumList(2,4); -- Type from the package. n2 NumList := NumList(6,8); -- Local type.BEGIN pkg.print_numlist(n1);-- The packaged procedure can't accept a value of the local type. pkg.print_numlist(n2); -- Causes a compilation error.END;/

DROP PACKAGE pkg;

2 番目のプロシージャ・コールは失敗します。これは、パッケージおよびローカルのVARRAY型は定義が同一でも互換性がないためです。

PL/SQL レコードレコードレコードレコードレコードレコードレコードレコードはフィールドフィールドフィールドフィールドに格納されるいくつかの関連したデータ項目のグループであり、それぞれに独自の名前とデータ型があります。レコードは、表の行または表の行の一部の列を保持する変数と考えることができます。フィールドは表の列に対応しています。

%ROWTYPE属性を使用すると、すべての列をリストせずに、データベースの表の中の行を表すレコードを宣言できます。記述したコードは、表に列が追加された後でも正常に動作します。表の列のサブセット、または複数の表の列を表現する場合、ビューを定義するかカーソルを宣言して正しい列を選択し、必要な結合を実行した後、ビューまたはカーソルに%ROWTYPEを適用します。

レコードの定義と宣言レコードの定義と宣言レコードの定義と宣言レコードの定義と宣言レコードを作成するには、RECORD型を定義してから、その型のレコードを宣言します。目的の値を含む表、ビューまたは PL/SQL カーソルを作成または検索し、%ROWTYPE属性を使用して一致するレコードを作成することもできます。

PL/SQL のコレクションおよびレコードの使用 5-41

Page 180: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードの定義と宣言

RECORD型は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で定義できます。独自の RECORD型を定義する際は、フィールドに NOT NULL制約を指定したり、フィールドにデフォルト値を指定することができます。

DECLARE-- Declare a record type with 3 fields. TYPE rec1_t IS RECORD (field1 VARCHAR2(16), field2 NUMBER, field3 DATE);-- For any fields declared NOT NULL, we must supply a default value. TYPE rec2_t IS RECORD (id INTEGER NOT NULL := -1, name VARCHAR2(64) NOT NULL := '[anonymous]');

-- Declare record variables of the types declared above. rec1 rec1_t; rec2 rec2_t;

-- Declare a record variable that can hold a row from the EMPLOYEES table.-- The fields of the record automatically match the names and types of the columns.-- Don't need a TYPE declaration in this case. rec3 employees%ROWTYPE;

-- Or we can mix fields that are table columns with user-defined fields. TYPE rec4_t IS RECORD (first_name employees.first_name%TYPE, last_name employees.last_name%TYPE, rating NUMBER); rec4 rec4_t;

BEGIN-- Read and write fields using dot notation rec1.field1 := 'Yesterday'; rec1.field2 := 65; rec1.field3 := TRUNC(SYSDATE-1);

-- We didn't fill in the NAME field, so it takes the default value declared above. dbms_output.put_line(rec2.name);END;/

データベースにレコードを格納する場合、そのレコードのフィールドと表の列が一致していれば、INSERT文または UPDATE文でそのレコードを指定できます。

%TYPEを使用して、表の列の型に対応するフィールドの型を指定できます。記述したコードは、列の型が変更された(たとえば、VARCHAR2の長さを伸ばしたり、NUMBERの精度を高くした)場合でも、正常に動作します。次の例では、部門の情報を保持するための RECORD型を指定しています。

DECLARE-- Best: use %ROWTYPE instead of specifying each column.-- Using <cursor>%ROWTYPE instead of <table>%ROWTYPE since we only want some columns.

5-42 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 181: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードの定義と宣言

-- Declaring the cursor doesn't run the query, so no performance hit. CURSOR c1 IS SELECT department_id, department_name, location_id FROM departments; rec1 c1%ROWTYPE;

-- Use <column>%TYPE in field declarations to avoid problems if the column types change. TYPE DeptRec2 IS RECORD (dept_id departments.department_id%TYPE, dept_name departments.department_name%TYPE, dept_loc departments.location_id%TYPE); rec2 DeptRec2;

-- Final technique, writing out each field name and specifying the type directly, is-- clumsy and unmaintainable for working with table data. Use only for all-PL/SQL code. TYPE DeptRec3 IS RECORD (dept_id NUMBER, dept_name VARCHAR2(14), dept_loc VARCHAR2(13)); rec3 DeptRec3;BEGIN NULL;END;/

PL/SQL を使用すると、オブジェクト、コレクションおよびその他のレコード(ネストしたレコード)を含むレコードを定義できます。ただし、レコードをオブジェクト型の属性にすることはできません。

プロシージャのパラメータおよびファンクションの戻り値としてのレコープロシージャのパラメータおよびファンクションの戻り値としてのレコープロシージャのパラメータおよびファンクションの戻り値としてのレコープロシージャのパラメータおよびファンクションの戻り値としてのレコードの使用ドの使用ドの使用ドの使用

レコードは、ストアド・プロシージャを使用すると簡単に処理できます。これは、渡すパラメータが 1 つのみで、各フィールドに個別のパラメータを渡す必要がないためです。たとえば、EMPLOYEES表から表の行をフェッチしてレコードに格納し、従業員の有給休暇またはその他の抽象的な値を計算するファンクションにその行をパラメータとして渡すと想定します。ファンクションは、レコードのフィールドを参照することで従業員に関するすべての情報にアクセスできます。

次の例は、ファンクションからレコードを戻す方法を示しています。複数のストアド・ファンクションおよびストアド・プロシージャからレコード型を参照できるようにするには、パッケージ仕様部でそのレコード型を宣言します。

DECLARE TYPE EmpRec IS RECORD ( emp_id NUMBER(4) last_name VARCHAR2(10), dept_num NUMBER(2), job_title VARCHAR2(9), salary NUMBER(7,2));

PL/SQL のコレクションおよびレコードの使用 5-43

Page 182: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

FUNCTION nth_highest_salary (n INTEGER) RETURN EmpRec IS ...BEGIN NULL;END;/

スカラー変数と同様に、ユーザー定義のレコードもプロシージャやファンクションの仮パラメータとして宣言できます。

DECLARE TYPE EmpRec IS RECORD ( emp_id emp.empno%TYPE, last_name VARCHAR2(10), job_title VARCHAR2(9), salary NUMBER(7,2)); ... PROCEDURE raise_salary (emp_info EmpRec);BEGIN ...END;/

レコードへの値の代入レコードへの値の代入レコードへの値の代入レコードへの値の代入レコード内のすべてのフィールドにデフォルト値を設定するには、同じ型の初期化されていないレコードをそのフィールドに代入します。

DECLARE TYPE RecordTyp IS RECORD (field1 NUMBER, field2 VARCHAR2(32) DEFAULT 'something'); rec1 RecordTyp; rec2 RecordTyp;BEGIN-- At first, rec1 has the values we assign. rec1.field1 := 100; rec1.field2 := 'something else';-- Assigning an empty record to rec1 resets fields to their default values.-- Field1 is NULL and field2 is 'something' (because of the DEFAULT clause above). rec1 := rec2; dbms_output.put_line('Field1 = ' || NVL(TO_CHAR(rec1.field1),'<NULL>') || ', field2 = ' || rec1.field2);END;/

5-44 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 183: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

ドット表記法を使用した代入文を使用して、レコードのフィールドに値を代入できます。

emp_info.last_name := 'Fields';

レコード中の個々のフィールドに別々に値を代入するかわりに、すべてのフィールドに値を一度に代入できます。

2 つのユーザー定義レコードのデータ型が同じであれば、一方のレコードをもう一方のレコードに代入できます。正確に一致するフィールドが含まれているのみでは不十分です。次の例を考えます。

DECLARE-- Two identical type declarations. TYPE DeptRec1 IS RECORD ( dept_num NUMBER(2), dept_name VARCHAR2(14)); TYPE DeptRec2 IS RECORD ( dept_num NUMBER(2), dept_name VARCHAR2(14)); dept1_info DeptRec1; dept2_info DeptRec2; dept3_info DeptRec2;BEGIN-- Not allowed; different datatypes, even though fields are the same.-- dept1_info := dept2_info; -- This assignment is OK because the records have the same type. dept2_info := dept3_info;END;/

フィールドの数と順序が同じで、対応するフィールドのデータ型が同じであれば、%ROWTYPEレコードをユーザー定義のレコードに代入できます。

DECLARE TYPE RecordTyp IS RECORD (last employees.last_name%TYPE, id employees.employee_id%TYPE); CURSOR c1 IS SELECT last_name, employee_id FROM employees;

-- Rec1 and rec2 have different types. But because rec2 is based on a %ROWTYPE, we can-- assign is to rec1 as long as they have the right number of fields and the fields-- have the right datatypes. rec1 RecordTyp; rec2 c1%ROWTYPE;BEGIN SELECT last_name, employee_id INTO rec2 FROM employees WHERE ROWNUM < 2; rec1 := rec2; dbms_output.put_line('Employee #' || rec1.id || ' = ' || rec1.last);END;/

PL/SQL のコレクションおよびレコードの使用 5-45

Page 184: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

SELECT文または FETCH文を使用して列の値をフェッチし、レコードに代入することもできます。選択リストの列が、レコード中のフィールドと同じ順序で並ぶようにしてください。

DECLARE TYPE RecordTyp IS RECORD (last employees.last_name%TYPE, id employees.employee_id%TYPE); rec1 RecordTyp;BEGIN SELECT last_name, employee_id INTO rec1 FROM employees WHERE ROWNUM < 2; dbms_output.put_line('Employee #' || rec1.id || ' = ' || rec1.last);END;/

代入文を使用してレコードに値のリストを代入することはできません。レコード用のコンストラクタのような表記は存在しません。

レコードの比較レコードの比較レコードの比較レコードの比較レコードが NULL であるかどうかテストしたり、等しいかどうか比較することはできません。

このような比較を実行する場合は、パラメータとして 2 つのレコードを受け入れ、対応するフィールドに対して適切なチェックまたは比較を実行する、独自のファンクションを記述します。

PL/SQL レコードのデータベースへの挿入レコードのデータベースへの挿入レコードのデータベースへの挿入レコードのデータベースへの挿入INSERT文の PL/SQL のみの拡張機能によって、VALUES句で、フィールドのリストではなく RECORD型または %ROWTYPE型の単一の変数を使用して、レコードをデータベース行に挿入できます。その結果、コードが読みやすくなり、メンテナンスが容易になります。

FORALL文を使用して INSERT文を発行すると、レコードのコレクション全体の値を挿入できます。

レコード内のフィールドの数は、INTO句にリストされている列数と等しい必要があります。また、対応するフィールドと列のデータ型には互換性が必要です。レコードと表との互換性を確実に保持するには、変数を table_name%ROWTYPE型として宣言することが も便利です。

5-46 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 185: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

例例例例 5-34 %ROWTYPE を使用したを使用したを使用したを使用した PL/SQL レコードの挿入レコードの挿入レコードの挿入レコードの挿入

この例では、%ROWTYPE修飾子を使用してレコード変数を宣言しています。この変数は、列リストを指定せずに挿入できます。%ROWTYPE宣言によって、表の列と同じ名前と型をレコードの属性に設定できます。

DECLARE dept_info dept%ROWTYPE;BEGIN-- deptno, dname, and loc are the table columns.-- The record picks up these names from the %ROWTYPE. dept_info.deptno := 70; dept_info.dname := 'PERSONNEL'; dept_info.loc := 'DALLAS';-- Using the %ROWTYPE means we can leave out the column list-- (deptno, dname, loc) from the INSERT statement. INSERT INTO dept VALUES dept_info;END;/

PL/SQL レコード値を使用したデータベースの更新レコード値を使用したデータベースの更新レコード値を使用したデータベースの更新レコード値を使用したデータベースの更新UPDATE文の PL/SQL のみの拡張機能によって、SET句の右側にフィールドのリストではなく RECORD型または %ROWTYPE型の単一の変数を使用して、データベース行を更新できます。

FORALL文を使用して UPDATE文を発行すると、レコードのコレクション全体の値を使用して行セットを更新できます。

また、UPDATE文を使用して、RETURNING句でレコードを指定し、新しい値を取り出してレコードに代入することもできます FORALL文を使用して UPDATE文を発行すると、更新された行セットから値を取り出してレコードのコレクションに代入できます。

レコード内のフィールドの数は、SET句にリストされている列数と等しい必要があります。また、対応するフィールドと列のデータ型には互換性が必要です。

例例例例 5-35 レコードを使用した行の更新レコードを使用した行の更新レコードを使用した行の更新レコードを使用した行の更新

キーワード ROWを使用すると、行全体を表現できます。

DECLARE dept_info dept%ROWTYPE;BEGIN dept_info.deptno := 30; dept_info.dname := 'MARKETING'; dept_info.loc := 'ATLANTA';-- The row will have values for the filled-in columns, and null-- for any other columns.

PL/SQL のコレクションおよびレコードの使用 5-47

Page 186: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

UPDATE dept SET ROW = dept_info WHERE deptno = 30;END;/

キーワード ROWを指定できる位置は、SET句の左側のみです。

SET ROWの引数には、単一の行のみを戻す副問合せではなく、実際の PL/SQL レコードを指定する必要があります。

レコードには、コレクションまたはオブジェクトも含めることができます。

例例例例 5-36 レコードを使用したレコードを使用したレコードを使用したレコードを使用した RETURNING 句の使用句の使用句の使用句の使用

INSERT文、UPDATE文および DELETE文には、RETURNING句を含めることができます。この句は、影響のある行の列値を PL/SQL レコード変数に戻します。これによって、挿入や更新の後、または削除の前に、行を SELECTで選択する必要がなくなります。

デフォルトでは、この句が使用できるのは、厳密に 1 つの行で操作する場合のみです。バルク SQL を使用する場合、RETURNING BULK COLLECT INTO形式を使用して、1 つ以上のコレクションに結果を格納できます。

次の例では、従業員の給与を更新し、従業員の名前、肩書きおよび新しい給与をレコード変数に取り出しています。

DECLARE TYPE EmpRec IS RECORD (last_name employees.last_name%TYPE, salary employees.salary%TYPE); emp_info EmpRec; emp_id NUMBER := 100;BEGIN UPDATE employees SET salary = salary * 1.1 WHERE employee_id = emp_id RETURNING last_name, salary INTO emp_info; dbms_output.put_line('Just gave a raise to ' || emp_info.last_name || ', who now makes ' || emp_info.salary); ROLLBACK;END;/

5-48 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 187: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

レコードの挿入レコードの挿入レコードの挿入レコードの挿入 / 更新に関する制約更新に関する制約更新に関する制約更新に関する制約現在、レコードの挿入 / 更新には、次の制約があります。

� レコード変数が使用できるのは、次の位置に限定されます。

� UPDATE文の SET句の右側

� INSERT文の VALUES句の中

� RETURNING句の INTO副次句の中

レコード変数は、SELECTリスト、WHERE句、GROUP BY句または ORDER BY句では使用できません。

� キーワード ROWを指定できる位置は、SET句の左側のみです。また、ROWと副問合せは一緒に使用できません。

� UPDATE文では、ROWが使用されている場合、許可される SET句は 1 つのみです。

� INSERT文の VALUES句にレコード変数が含まれている場合は、その句の中で他の変数または値を使用することはできません。

� RETURNING句の INTO副次句にレコード変数が含まれている場合は、その副次句の中で他の変数または値を使用することはできません。

� 次の内容はサポートされません。

� ネストしたレコード型

� レコードを戻すファンクション

� EXECUTE IMMEDIATE文を使用したレコードの挿入および更新

レコードのコレクションへのデータの問合せレコードのコレクションへのデータの問合せレコードのコレクションへのデータの問合せレコードのコレクションへのデータの問合せSELECT INTO文または FETCH文に BULK COLLECT INTO句を使用すると、行セットを取り出してレコードのコレクションに代入できます。

DECLARE TYPE EmployeeSet IS TABLE OF employees%ROWTYPE; underpaid EmployeeSet; -- Holds set of rows from EMPLOYEES table.

CURSOR c1 IS SELECT first_name, last_name FROM employees; TYPE NameSet IS TABLE OF c1%ROWTYPE; some_names NameSet; -- Holds set of partial rows from EMPLOYEES table.

BEGIN-- With one query, we bring all the relevant data into the collection of records. SELECT * BULK COLLECT INTO underpaid FROM employees WHERE salary < 2500 ORDER BY salary DESC;

PL/SQL のコレクションおよびレコードの使用 5-49

Page 188: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコードへの値の代入

-- Now we can process the data by examining the collection, or passing it to-- a separate procedure, instead of writing a loop to FETCH each row. dbms_output.put_line(underpaid.COUNT || ' people make less than 2500.'); FOR i IN underpaid.FIRST .. underpaid.LAST LOOP dbms_output.put_line(underpaid(i).last_name || ' makes ' || underpaid(i).salary); END LOOP;

-- We can also bring in just some of the table columns.-- Here we get the first and last names of 10 arbitrary employees. SELECT first_name, last_name BULK COLLECT INTO some_names FROM employees WHERE ROWNUM < 11; FOR i IN some_names.FIRST .. some_names.LAST LOOP dbms_output.put_line('Employee = ' || some_names(i).first_name || ' ' || some_names(i).last_name); END LOOP;END;/

5-50 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 189: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での SQL 操作の

6

PL/SQL でのでのでのでの SQL 操作の実行操作の実行操作の実行操作の実行

この章では、Oracle データを操作するための SQL コマンド、ファンクションおよび演算子が PL/SQL でどのようにサポートされているかを示します。

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

� PL/SQL における SQL サポートの概要(6-2 ページ)

� PL/SQL での DML 操作の実行(INSERT、UPDATE および DELETE)(6-6 ページ)

� PL/SQL での問合せの発行(6-9 ページ)

� PL/SQL を使用したデータの問合せ(6-11 ページ)

� PL/SQL を使用したデータの問合せ : 明示カーソルの FOR ループ(6-12 ページ)

� カーソル変数(REF CURSOR)の使用(6-25 ページ)

� カーソル式の使用(6-35 ページ)

� PL/SQL におけるトランザクション処理の概要(6-38 ページ)

� 自律型トランザクションによる独立した作業単位の実行(6-45 ページ)

実行 6-1

Page 190: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL における SQL サポートの概要

PL/SQL におけるにおけるにおけるにおける SQL サポートの概要サポートの概要サポートの概要サポートの概要SQL を拡張した PL/SQL は、優れた性能に加えて、使いやすさも実現しています。PL/SQLは、EXPLAIN PLAN以外のすべての SQL データ操作文、トランザクション制御文、ファンクション、疑似列および演算子を完全にサポートしているため、Oracle データを柔軟かつ安全に操作できます。また、動的 SQL もサポートしているため、SQL データ定義文、データ制御文、セッション制御文を動的に実行できます。さらに、PL/SQL は、現行の ANSI/ISO SQL 規格に準拠しています。

データ操作データ操作データ操作データ操作Oracle データを操作するには、INSERTコマンド、UPDATEコマンド、DELETEコマンド、SELECTコマンドおよび LOCK TABLEコマンドを使用します。INSERTで、データベースの表に新しいデータ行を追加します。UPDATEで、行を変更します。DELETEで、不要な行を削除します。SELECTで、検索基準に合う行を取り出します。LOCK TABLEで、表へのアクセスを一時的に制限します。

トランザクション制御トランザクション制御トランザクション制御トランザクション制御Oracle では、トランザクションに基づいて作業します。つまり、トランザクションを使用してデータの整合性を確保します。トランザクションとは、論理作業単位を実行する一連のSQL の DML 文です。たとえば、2 つの UPDATE文を使用して、ある銀行口座に入金し、別の口座から出金します。一方の操作は成功するが他方の操作は失敗するという状態を許可しないことが重要です。

Oracle は、データベースを変更するトランザクションの終わりに、すべての変更内容を確定または取消しします。トランザクション中にプログラムに障害が発生すると、Oracle がエラーを検出してトランザクションをロールバックし、データベースを元の状態にリストアします。

COMMITコマンド、ROLLBACKコマンド、SAVEPOINTコマンドおよび SET TRANSACTIONコマンドを使用して、トランザクションを制御します。COMMITは、カレント・トランザクション中にデータベースに加えられた変更内容を確定します。ROLLBACKは、カレント・トランザクションを終了させ、トランザクションの開始以降に加えられた変更をすべて取り消します。SAVEPOINTは、トランザクション処理内の現在位置にマークを付けます。ROLLBACKと SAVEPOINTを併用すると、トランザクションの一部のみを取り消すことができます。SET TRANSACTIONは、読取り / 書込みアクセスや分離レベルなど、トランザクションのプロパティを設定します。

6-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 191: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL における SQL サポートの概要

SQL ファンクションファンクションファンクションファンクションSQL ファンクションをコールする問合せの例を次に示します。

DECLARE job_count NUMBER; emp_count NUMBER;BEGIN SELECT COUNT(DISTINCT job_id) INTO job_count FROM employees; SELECT COUNT(*) INTO emp_count FROM employees;END;/

SQL 疑似列疑似列疑似列疑似列PL/SQL では、SQL 擬似列 CURRVAL、LEVEL、NEXTVAL、ROWIDおよび ROWNUMが認識されます。PL/SQL では、SQL 問合せの中でのみ疑似列を使用できます。INSERT文、UPDATE文、DELETE文、または代入や条件テストなどの他の PL/SQL 文では使用できません。

CURRVAL とととと NEXTVAL順序順序順序順序とは、連続的な数値を生成するスキーマ・オブジェクトのことです。順序を作成する場合は、その初期値と増分を指定できます。CURRVALは指定された順序の中での現在の値を戻します。

セッションの中で CURRVALを参照する前に、NEXTVALを使用して数値を生成する必要があります。NEXTVALを参照すると、現在の順序番号が CURRVALに格納されます。NEXTVALは順序に増分を加えて、次の値を戻します。順序の現在の値または次の値を得るには、ドット表記法を使用します。

sequence_name.CURRVALsequence_name.NEXTVAL

順序を作成すると、トランザクション処理の目的のために独自の順序番号を生成させることができます。CURRVALおよび NEXTVALは、SELECTリスト、VALUES句および SET句の中でしか使用できません。次の例は、新しい順序番号を生成し、複数の文の中で同じ番号を参照する方法を示しています。

CREATE TABLE employees_temp AS SELECT employee_id, first_name FROM employees;CREATE TABLE employees_temp2 AS SELECT employee_id, first_name FROM employees;

DECLARE next_value NUMBER;BEGIN-- The NEXTVAL value is the same no matter what table you select from. SELECT employees_seq.NEXTVAL INTO next_value FROM dual;

PL/SQL での SQL 操作の実行 6-3

Page 192: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL における SQL サポートの概要

-- You usually use NEXTVAL to create unique numbers when inserting data. INSERT INTO employees_temp VALUES (employees_seq.NEXTVAL, 'value 1');-- If you need to store the same value somewhere else, you use CURRVAL. INSERT INTO employees_temp2 VALUES (employees_seq.CURRVAL, 'value 1');-- Because NEXTVAL values might be referenced by different users and-- applications, and some NEXTVAL values might not be stored in the-- database, there might be gaps in the sequence.END;/

DROP TABLE employees_temp;DROP TABLE employees_temp2;

順序の NEXTVAL値を参照するたびに、トランザクションをコミットするかロールバックするかにかかわらず、順序はすぐに増分され、その変化は永続的になります。

LEVELSELECT CONNECT BY文で LEVELを使用すると、データベース表の行をツリー構造に整理できます。順序番号を使用して各行に一意の識別子を指定し、他の行からこれらの識別子を参照して親子関係を構築できます。

LEVELはツリー構造の中のノードのレベル番号を戻します。ルートはレベル 1、ルートの子はレベル 2、孫はレベル 3、のように続きます。

ツリーのルートを識別する条件は、START WITH句で指定します。PRIOR演算子を使用して、問合せがツリーの中を移動するときの向き(ルートから下へ、または枝から上へ)を指定します。

ROWIDROWIDはデータベース表の行の ROWID(バイナリ・アドレス)を戻します。UROWID型の変数を使用すると、ROWID を読取り可能な書式で格納できます。

物理 ROWID を選択またはフェッチして UROWID変数に入れる場合は、バイナリ値を文字列に変換するファンクション ROWIDTOCHARを使用します。UPDATE文または DELETE文のWHERE句の中で UROWID変数と ROWID疑似列を比較すると、カーソルからフェッチされた新の行を識別できます。例は、6-44 ページの「コミットにまたがるフェッチ」を参照して

ください。

ROWNUMROWNUMは、行が表から取り出された順番を示す番号を戻します。 初に取り出された行のROWNUMは 1、2 番目に取り出された行の ROWNUMは 2、のように続きます。SELECT文にORDER BY句が含まれている場合、取り出された行がソートされる前に、行に ROWNUMが割り当てられます。ソートされた 初の n 個の行を取得するには、(次の例に示すとおり)副問合せを使用します。

6-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 193: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL における SQL サポートの概要

UPDATE文で ROWNUMを使用して、表の中の個々の行に一意の値を代入できます。また、SELECT文の WHERE句で ROWNUM を使用して、取り出される行の数を制限できます。

CREATE TABLE employees_temp AS SELECT * FROM employees;

DECLARE CURSOR c1 IS SELECT employee_id, salary FROM employees_temp WHERE salary > 2000 AND ROWNUM <= 10; -- 10 arbitrary rows CURSOR c2 IS SELECT * FROM (SELECT employee_id, salary FROM employees_temp WHERE salary > 2000 ORDER BY salary DESC) WHERE ROWNUM < 5; -- first 5 rows, in sorted orderBEGIN-- Each row gets assigned a different number UPDATE employees_temp SET employee_id = ROWNUM;END;/

DROP TABLE employees_temp;

ROWNUMの値が増えるのは、行が取り出されたときのみです。つまり、WHERE句で ROWNUMを使用する場合は、次のようにする必要があります。

... WHERE ROWNUM < constant;

... WHERE ROWNUM <= constant;

SQL 演算子演算子演算子演算子PL/SQL では、SQL 文の中で、SQL の比較演算子、集合演算子および行演算子を使用できます。この項では、これらの演算子について簡単に説明します。詳細は、『Oracle Database SQL リファレンス』を参照してください。

比較演算子比較演算子比較演算子比較演算子

比較演算子は、通常、DML 文の WHERE句で述語を形成するために使用します。述語は、2つの式を比較して、TRUE、FALSE、NULLのいずれかに評価します。次の比較演算子は、述語の形成に使用できます。述語は論理演算子 AND、ORおよび NOTを使用して結合できます。

演算子演算子演算子演算子 説明説明説明説明

ALL 値をリストのすべての値、または副問合せが戻したすべての値と 1 つずつ比較して、結果がすべて TRUEで

あれば TRUEに評価します。

ANY、SOME 値をリストのすべての値、または副問合せが戻したすべての値と 1 つずつ比較して、結果のいずれかが TRUEであれば TRUEに評価します。

PL/SQL での SQL 操作の実行 6-5

Page 194: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での DML 操作の実行(INSERT、UPDATE および DELETE)

集合演算子集合演算子集合演算子集合演算子

集合演算子は 2 つの問合せの結果を組み合せて 1 つの結果を戻します。INTERSECTによって、2 つの問合せの両方で選択されたすべての行を、重複するものを除いて戻します。MINUSは、1 番目の問合せによって選択されたが、2 番目の問合せでは選択されなかったすべての行を、重複するものを除いて戻します。UNIONによって、2 つの問合せのいずれかで選択されたすべての行を、重複するものを除いて戻します。UNION ALLは、重複した行も含めて、どちらかの問合せによって選択されたすべての行を戻します。

行演算子行演算子行演算子行演算子

行演算子は特定の行を戻すか、または参照します。ALLによって、問合せの結果や集合式に含まれる重複した行をそのまま残します。DISTINCTは、問合せの結果や集合式に含まれる重複した行を削除します。PRIORは、ツリー構造の問合せによって戻された現在行の親の行を参照します。

PL/SQL でのでのでのでの DML 操作の実行(操作の実行(操作の実行(操作の実行(INSERT、、、、UPDATE およびおよびおよびおよび DELETE))))INSERT文、UPDATE文および DELETE文は、PL/SQL プログラム内に直接記述できます。特別な表記法は必要ありません。

CREATE table1 AS SELECT object_name, object_type FROM user_objects;

BEGIN INSERT INTO table1(col1, col2) VALUES('value1','value2'); UPDATE table1 SET col1 = 'another value' WHERE col2 IS NULL; DELETE FROM table1 WHERE col1 = col2; COMMIT;END;/

DROP table1;

BETWEEN 値が指定範囲内かどうかをテストします。

EXISTS 副問合せが行を 1 つでも戻すと TRUEを戻します。

IN セット・メンバーシップをテストします。

IS NULL NULL かどうかをテストします。

LIKE 文字列が、指定したパターンと一致するかどうかをテストします。指定パターンにはワイルドカードを使用できます。

演算子演算子演算子演算子 説明説明説明説明

6-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 195: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での DML 操作の実行(INSERT、UPDATE および DELETE)

これらの文が影響を与える行の数を確認するには、SQL%ROWCOUNTの値をチェックします。

SET SERVEROUTPUT ON;BEGIN UPDATE employees SET salary = salary * 1.05 WHERE ...; dbms_output.put_line('Updated ' || SQL%ROWCOUNT || ' salaries.');END;/

リテラル値またはその他のプログラミング言語のバインド変数を使用するすべての箇所で、PL/SQL 変数を直接置き換えることができます。

CREATE table1 AS SELECT object_name, object_type FROM user_objects;

DECLARE x VARCHAR2(128) := 'value1'; y NUMBER := 10;BEGIN INSERT INTO table1(col1, col2) VALUES(x, x); UPDATE table1 SET col1 = x WHERE col3 < y; DELETE FROM table1 WHERE col1 = x; COMMIT;END;/

DROP table1;

この表記法では、WHERE句の値のかわりに変数を使用できます。表名や列名などのかわりに変数を使用するには、EXECUTE IMMEDIATE文が必要です。

暗黙カーソルの属性の概要暗黙カーソルの属性の概要暗黙カーソルの属性の概要暗黙カーソルの属性の概要暗黙カーソルの属性は、INSERT文、UPDATE文、DELETE文または SELECT INTO文の実行に関する情報を戻します。カーソル属性の値は、常に直前に実行された SQL 文を参照しています。Oracle が SQLカーソルをオープンするまでは、暗黙カーソルの属性の結果は NULLになります。

注意注意注意注意 : SQLカーソルには、FORALL文での使用に設計された別の属性 %BULK_ROWCOUNTがあります。詳細は、11-15 ページの「%BULK_ROWCOUNT 属性を持つ FORALL による影響を受ける行カウント」を参照してください。

PL/SQL での SQL 操作の実行 6-7

Page 196: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での DML 操作の実行(INSERT、UPDATE および DELETE)

%FOUND カーソル属性カーソル属性カーソル属性カーソル属性 : DML 文で行が変更されたかどうか文で行が変更されたかどうか文で行が変更されたかどうか文で行が変更されたかどうかSQL の DML 文が実行されるまでは、%FOUNDの結果は NULLになります。その後、INSERT文、UPDATE文または DELETE文が 1 行または複数の行に作用するか、またはSELECT INTO文が 1 行または複数の行を戻すと、%FOUNDの結果は TRUEになります。それ以外の場合、%FOUNDの結果は FALSEになります。次の例では、%FOUNDを使用して、削除に成功した場合に行を挿入するようにしています。

DELETE FROM emp WHERE empno = my_empno;IF SQL%FOUND THEN -- delete succeeded INSERT INTO new_emp VALUES (my_empno, my_ename, ...);

%ISOPEN カーソル属性カーソル属性カーソル属性カーソル属性 : 暗黙カーソルの場合は常に暗黙カーソルの場合は常に暗黙カーソルの場合は常に暗黙カーソルの場合は常に FALSEOracle は、SQL カーソルに対応付けられた SQL 文の実行を終了すると、この SQL カーソルを自動的にクローズします。その結果、%ISOPENの結果は常に FALSEになります。

%NOTFOUND 属性属性属性属性 : DML 文で行の変更が失敗したかどうか文で行の変更が失敗したかどうか文で行の変更が失敗したかどうか文で行の変更が失敗したかどうか%NOTFOUNDは、論理的に %FOUNDの逆です。INSERT文、UPDATE文または DELETE文がどの行にも作用しないか、または SELECT INTO文がどの行も戻さない場合、%NOTFOUNDの結果は TRUEになります。それ以外の場合、%NOTFOUNDの結果は FALSEになります。

%ROWCOUNT 属性属性属性属性 : これまでに影響を受けた行数これまでに影響を受けた行数これまでに影響を受けた行数これまでに影響を受けた行数%ROWCOUNTの結果は、INSERT文、UPDATE文または DELETE文の影響を受けた行、または SELECT INTO文に戻された行の数になります。INSERT文、UPDATE文または DELETE文がどの行にも作用しないか、または SELECT INTO文がどの行も戻さないと、%ROWCOUNTの結果は 0になります。次の例では、%ROWCOUNTを使用して、削除された行が 10 行を超えた場合にアクションを実行するようにしています。

DELETE FROM emp WHERE ...IF SQL%ROWCOUNT > 10 THEN -- more than 10 rows were deleted ...END IF;

SELECT INTO文が複数の行を戻した場合、PL/SQL によって事前定義の例外TOO_MANY_ROWSが呼び出され、%ROWCOUNTは、問合せを満たす行の実数ではなく、1になります。

暗黙カーソルの属性を使用する場合のガイドライン暗黙カーソルの属性を使用する場合のガイドライン暗黙カーソルの属性を使用する場合のガイドライン暗黙カーソルの属性を使用する場合のガイドラインカーソル属性の値は、常に直前に実行された SQL 文を参照します(その文の場所とは無関係です)。文が別の有効範囲に存在する場合もあります(サブブロックなど)。属性の値を保存して後で使用する場合は、値をブール変数にただちに代入してください。プロシージャ・コールなどの他の操作を実行すると、%NOTFOUNDの値がテスト前に変更される可能性があります。

6-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 197: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での問合せの発行

%NOTFOUND属性は、SELECT INTO文と組み合せて使用しても効果がありません。

SELECT INTO文が行を戻せなかった場合は、PL/SQL によって事前定義済の例外NO_DATA_FOUNDがただちに呼び出され、%NOTFOUNDをチェックする前に制御フローが中断されます。

SQL 集計関数をコールする SELECT INTO文は、常に値または NULL を戻します。このような文の後では、%NOTFOUND属性の値は常に FALSEになるため、属性をチェックする必要はありません。

SQL のののの INSERT 文および文および文および文および UPDATE 文での文での文での文での PL/SQL レコードの使用レコードの使用レコードの使用レコードの使用INSERT文および UPDATE文で PL/SQL レコードの各フィールドをリストするかわりに、PL/SQL レコードを直接使用できます。%ROWTYPE属性を使用してレコードを宣言すると、レコードのフィールドが SQL 表と同じになるため、これが も便利な方法です。

DECLARE emp_rec emp%ROWTYPE;BEGIN emp_rec.eno := 1500; emp_rec.ename := 'Steven Hill'; emp_rec.sal := '40000';-- A %ROWTYPE value can fill in all the row fields. INSERT INTO emp VALUES emp_rec;

-- The fields of a %ROWTYPE can completely replace the table columns. UPDATE emp SET ROW = emp_rec WHERE eno = 100;END;/

この方法では、PL/SQL の変数および型が SQL の DML 文と統合されますが、PL/SQL レコードを動的 SQL 文の中でバインド変数として使用することはできません。

PL/SQL での問合せの発行での問合せの発行での問合せの発行での問合せの発行PL/SQL を使用すると、問合せ(SQL の SELECT文)を実行し、結果セットの個別のフィールドまたはすべての行にアクセスできます。問合せの結果に対して実行する処理の複雑さに応じて、様々な表記法を使用できます。

参照参照参照参照 : PL/SQL レコードの詳細は、5-41 ページの「PL/SQL レコード」を参照してください。

PL/SQL での SQL 操作の実行 6-9

Page 198: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での問合せの発行

1 行のみの選択行のみの選択行のみの選択行のみの選択 : SELECT INTO 文文文文問合せが 1 行のみを戻すと予測している場合、通常の SQL の SELECT文に、結果を保持する PL/SQL 変数を指定する INTO句を追加して記述できます。

問合せが複数の行を戻す可能性があり、そのうち 初の値以外は必要ない場合、ROWNUMの値と比較することで、結果セットを 1 行に制限できます。

問合せが行を戻さない可能性がある場合、例外ハンドラを使用して、データが見つからない場合のアクションを指定します。

使用するデータに条件が存在するかどうかのチェックのみを行う場合、COUNT(*)演算子を使用して問合せを記述できます。この演算子は常に数値を戻すため、NO_DATA_FOUND例外は発生しません。

複数行の選択複数行の選択複数行の選択複数行の選択 : BULK COLLECT 句句句句1 回に 1 行ずつ結果セットをループするのではなく、ローカルの PL/SQL 変数に大量のデータを代入する必要がある場合、BULK COLLECT句を使用できます。特定の列のみを問い合せる場合、各列に対するすべての結果を個別のコレクション変数に格納できます。

SELECT employee_id, last_name, salary FROM employees BULK COLLECT INTO all_employee_ids, all_last_names, all_salaries;

表のすべての列を問い合せる場合は、レコードのコレクションに結果セット全体を格納できます。これによって、結果のループ処理および別の列への参照が簡単になります。

SELECT * FROM employees BULK COLLECT INTO all_employees;FOR i IN all_employees.FIRST .. all_employees.LASTLOOP ...END LOOP;

この方法では非常に高速に処理されますが、メモリーも集中的に使用されます。この方法を頻繁に使用する場合は、より多くの処理を SQL で実行すると、コードのパフォーマンスを向上できます。

� 結果セットを 1 回のみループする場合、FORループを使用します(これ以降の項を参照)。この方法を使用すると、結果セットのコピーを格納する際のメモリーのオーバーヘッドを回避できます。

� 結果セットをループして特定の値をスキャンしたり、結果をフィルタリングしてより小さい結果セットにする場合、かわりに元の問合せでスキャンまたはフィルタリングを行います。簡単な場合であれば WHERE句を追加できます。また、複数の結果セットを比較する場合は、INTERSECTや MINUSなどの集合演算子を使用できます。

6-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 199: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

� 結果セットをループして、各結果行に対して別の問合せまたは DML 文を実行する場合は、より効率的な方法があります。問合せの場合、元の問合せに副問合せまたはEXISTS句や NOT EXISTS句を含めることを検討してください。DML 文の場合、通常のループ内部でこれらの文をコーディングするより高速な FORALL文を使用することを検討してください。

複数行のループ複数行のループ複数行のループ複数行のループ : カーソルカーソルカーソルカーソル FOR ループループループループも一般的な問合せは、SELECT文を発行し、結果セットの行に対してただちにループを 1

回実行することす。PL/SQL では、単純な FORループを使用してこのような種類の問合せを実行できます。

FORループのイテレータ変数は、事前に宣言する必要はありません。イテレータ変数は、フィールド名が問合せの列名に一致する %ROWTYPEレコードです。この変数は、ループ中にのみ存在します。明示的な列名ではなく式を使用する場合、列の別名を使用すると、ループ内の対応する値を参照できます。

複雑な問合せの処理の実行複雑な問合せの処理の実行複雑な問合せの処理の実行複雑な問合せの処理の実行 : 明示カーソル明示カーソル明示カーソル明示カーソル問合せの処理を完全に制御するには、OPEN文、FETCH文および CLOSE文と明示カーソルを組み合せて使用します。

ある場所で問合せを指定し、他のサブプログラム内などの別の場所に行を取り出す必要がある場合があります。また、状況に応じて、ORDER BY句や GROUP BY句など、別の問合せパラメータを選択する必要がある場合もあります。さらに、一部の行に対して他の行とは異なる処理を行うために、より複雑なループが必要な場合もあります。

明示カーソルは非常に柔軟性があるため、必要に応じて様々な表記法から選択できます。次の項では、明示カーソルのすべての問合せ処理機能について説明します。

PL/SQL を使用したデータの問合せを使用したデータの問合せを使用したデータの問合せを使用したデータの問合せ従来のデータベース・プログラミングでは、カーソルカーソルカーソルカーソルと呼ばれる内部データ構造を使用して問合せの結果を処理していました。PL/SQL では、ほとんどの場合にカーソルを管理できるため、問合せの結果を処理するコードが単純で小型になります。この項では、PL/SQL によってすべてが管理される単純な問合せと、自分でカーソルを使用する複雑な問合せを処理する方法について説明します。

PL/SQL での SQL 操作の実行 6-11

Page 200: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

PL/SQL を使用したデータの問合せを使用したデータの問合せを使用したデータの問合せを使用したデータの問合せ : 暗黙カーソルの暗黙カーソルの暗黙カーソルの暗黙カーソルの FOR ループループループループPL/SQL を使用すると、問合せの発行、結果の各行の %ROWTYPEレコードへの取出し、およびループ内の各行の処理を簡単に実行できます。

� FORループ内に、問合せのテキストを直接含めます。

� PL/SQL によって、結果セットの列に対応するフィールドを持つレコード変数が作成されます。

� ループ内でこのレコード変数のフィールドを参照します。テストや計算、出力の表示または他の場所への結果の格納を実行できます。

SQL*Plus での実行例を次に示します。この例では、アクセス可能なすべての索引の名前および状態を取得する問合せを実行しています。

BEGIN FOR item IN ( SELECT object_name, status FROM user_objects WHERE object_type = 'INDEX' AND object_name NOT LIKE '%$%' ) LOOP dbms_output.put_line('Index = ' || item.object_name || ', Status = ' || item.status); END LOOP;END;/

FORループを反復する前に、PL/SQL は暗黙的に宣言したレコードに取り出した値を格納します。

ループの中の一連の文は、問合せを満たす 1 つの行について 1 回実行されます。ループを終了させると、カーソルは自動的にクローズされます。EXIT文または GOTO文を使用して、すべての行がフェッチされる前にループを終了させた場合やループの内側から例外が呼び出された場合も、カーソルはクローズされます。

13-107 ページの「LOOP 文」を参照してください。

PL/SQL を使用したデータの問合せを使用したデータの問合せを使用したデータの問合せを使用したデータの問合せ : 明示カーソルの明示カーソルの明示カーソルの明示カーソルの FOR ループループループループ同じプロシージャの別の部分から同じ問合せを参照する必要がある場合、その問合せを指定するカーソルを宣言し、FOR ループを使用して結果を処理できます。

次の PL/SQL ブロックでは、同じ問合せを 2 通りの方法で実行しています。 初はアクセス可能なすべての表を検索し、次はアクセス可能なすべての索引を検索しています。

DECLARE CURSOR c1 IS SELECT object_name, status FROM user_objects WHERE object_type = 'TABLE'

6-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 201: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

AND object_name NOT LIKE '%$%';BEGIN FOR item IN c1 LOOP dbms_output.put_line('Table = ' || item.object_name || ', Status = ' || item.status); END LOOP;END;/

13-107 ページの「LOOP 文」を参照してください。

カーソルカーソルカーソルカーソル FOR ループ内の式の別名の定義ループ内の式の別名の定義ループ内の式の別名の定義ループ内の式の別名の定義カーソル FOR ループでは、PL/SQL によって、結果セットの列に対応するフィールドを持つ %ROWTYPEレコードが作成されます。フィールドは、SELECTリストの中の対応する列と同じ名前を持ちます。

選択リストには、列と定数、連結された 2 つの列などの式が含まれる場合があります。この場合、列の別名を使用して、適切な列に一意の名前を付けます。

次の例では、full_nameおよび dream_salaryが問合せの中で式の別名として使用されています。

SET SERVEROUTPUT ON;

BEGIN FOR item IN ( SELECT first_name || ' ' || last_name AS full_name, salary * 10 AS dream_salary FROM employees WHERE ROWNUM <= 5 ) LOOP dbms_output.put_line(item.full_name || ' dreams of making ' || item.dream_salary); END LOOP;END;/

PL/SQL での SQL 操作の実行 6-13

Page 202: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

明示カーソルの概要明示カーソルの概要明示カーソルの概要明示カーソルの概要問合せの処理を完全に制御する必要がある場合、PL/SQL ブロック、サブプログラムまたはパッケージの宣言部の中でカーソルを明示的に宣言できます。

カーソルの制御には、OPEN、FETCHおよび CLOSEの 3 つのコマンドを使用します。まず、結果セットを識別する OPEN文でカーソルを初期化します。次に、FETCHを繰り返し実行して、すべての行を取り出します。または BULK COLLECT句を使用して、すべての行を一度にフェッチします。 後の行の処理が終わってから、CLOSE文でカーソルを解放します。

この方法では、暗黙カーソルの FOR ループなどの他の方法より多くのコードが必要になります。この方法のメリットは柔軟性があるということです。この方法では次の操作を実行できます。

� 複数のカーソルを宣言してオープンすることで、複数の問合せをパラレルで処理できます。

� 1 回のループで複数の行を処理したり、行をスキップしたり、処理を複数のループに分割することができます。

カーソルの宣言カーソルの宣言カーソルの宣言カーソルの宣言他の文でカーソルを参照するときは、事前に宣言する必要があります。カーソルに名前を付け、特定の問合せと関連付けます。オプションで、カーソルの戻り型

(table_name%ROWTYPEなど)を宣言することもできます。また、オプションで、ローカル変数を参照するかわりに WHERE句で使用するパラメータを指定することもできます。これらのパラメータには、デフォルト値を設定できます。

たとえば、次のようにカーソルを宣言できます。

DECLARE CURSOR c1 IS SELECT empno, ename, job, sal FROM emp WHERE sal > 2000; CURSOR c2 RETURN dept%ROWTYPE IS SELECT * FROM dept WHERE deptno = 10;

カーソルは PL/SQL 変数ではありません。カーソルに値を代入したり、カーソルを式の中で使用することはできません。カーソルと変数は、同じ有効範囲規則に従います。データベース表に基づいてカーソルに名前を付けることができますが、お薦めしません。

カーソルはパラメータを取ることができます。カーソルのパラメータは、カーソルに結び付けられた問合せの中で、定数が使用可能な位置であればどこででも使用できます。カーソルの仮パラメータは INパラメータにする必要があります。このパラメータは問合せに値を提供しますが、問合せから値を戻しません。カーソル・パラメータに NOT NULL制約を課すことはできません。

6-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 203: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

次の例に示すように、カーソルのパラメータをデフォルト値に初期化できます。初期化すると、必要に応じてデフォルト値を受け入れたり上書きすることで、カーソルの実パラメータに様々な数値を渡すことができます。また、カーソルへの既存の参照を変更しなくても、新しい仮パラメータを追加できます。

DECLARE CURSOR c1 (low INTEGER DEFAULT 0, high INTEGER DEFAULT 99) IS SELECT ...

カーソルのパラメータは、カーソル宣言で指定されている問合せの範囲からしか参照できません。パラメータ値は、カーソルがオープンされているときに、カーソルに関連付けられた問合せから使用できます。

カーソルのオープンカーソルのオープンカーソルのオープンカーソルのオープンカーソルをオープンすると、問合せが実行され、結果セットが識別されます(結果セットは、問合せの検索条件に一致するすべての行で構成されています)。FOR UPDATE句を使用して宣言されたカーソルの場合、OPEN文はこれらの行のロックもします。OPEN文の例を次に示します。

DECLARE CURSOR c1 IS SELECT ename, job FROM emp WHERE sal < 3000; ...BEGIN OPEN c1; ...END;

結果セット内の行は、OPEN文の実行時ではなく、FETCHによって取り出されます。

カーソルを使用したフェッチカーソルを使用したフェッチカーソルを使用したフェッチカーソルを使用したフェッチBULK COLLECT句(次の項で説明)を使用していない場合は、FETCH文によって結果セットの行が一度に 1 行ずつ取り出されます。各 FETCH 文は現在の行を取り出してから、カーソルを結果セットの次の行に進めます。

各列を個別の変数に格納したり、行全体を適切なフィールドを持つレコード(通常は%ROWTYPEを使用して宣言する)に格納することができます。

-- This cursor queries 3 columns.-- Each column is fetched into a separate variable.FETCH c1 INTO my_empno, my_ename, my_deptno;-- This cursor was declared as SELECT * FROM employees.-- An entire row is fetched into the my_employees record, which-- is declared with the type employees%ROWTYPE.FETCH c2 INTO my_employees;

PL/SQL での SQL 操作の実行 6-15

Page 204: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

カーソルと関連付けられた問合せが戻す列の値に対しては、INTOリストの中に、対応する、型互換の変数が存在している必要があります。通常は、次のように FETCH文を使用します。

LOOP FETCH c1 INTO my_record; EXIT WHEN c1%NOTFOUND; -- process data recordEND LOOP;

問合せは、有効範囲内にある PL/SQL 変数を参照できます。問合せの中の変数は、カーソルがオープンされたときにのみ評価されます。次の例では、FETCH 文が実行されるたびにfactorに増分が加えられていますが、取り出された給与はそれぞれ 2倍されます。

DECLARE my_sal employees.salary%TYPE; my_job employees.job_id%TYPE; factor INTEGER := 2; CURSOR c1 IS SELECT factor*salary FROM employees WHERE job_id = my_job;BEGIN OPEN c1; -- here factor equals 2 LOOP FETCH c1 INTO my_sal; EXIT WHEN c1%NOTFOUND; factor := factor + 1; -- does not affect FETCH END LOOP;END;/

結果セットや問合せの中の変数の値を変更する場合は、カーソルをクローズし、入力変数を新しい値に設定して、再オープンする必要があります。

ただし、同じカーソルを使用して、別々の FETCH 文で、異なる INTOリストを使用できます。個々の FETCH 文で別の行を取り出し、ターゲット変数に値を代入します。次に例を示します。

DECLARE CURSOR c1 IS SELECT last_name FROM employees ORDER BY last_name; name1 employees.last_name%TYPE; name2 employees.last_name%TYPE; name3 employees.last_name%TYPE;BEGIN OPEN c1; FETCH c1 INTO name1; -- this fetches first row FETCH c1 INTO name2; -- this fetches second row FETCH c1 INTO name3; -- this fetches third row CLOSE c1;END;/

6-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 205: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL を使用したデータの問合せ

FETCH 文を実行した時点で結果セットに行が残っていなかった場合、ターゲット変数の値は未定義になります。

注意注意注意注意 : 結果として、FETCH文は行を戻すことに失敗します。この状況が発生しても、例外は呼び出されません。失敗を検出するには、カーソル属性 %FOUNDまたは %NOTFOUNDを使用します。詳細は、6-35 ページの「カーソル式の使用」を参照してください。

カーソルを使用したバルク・データのフェッチカーソルを使用したバルク・データのフェッチカーソルを使用したバルク・データのフェッチカーソルを使用したバルク・データのフェッチBULK COLLECT句を使用すると、結果セットのすべての行を一度にフェッチできます

(11-19 ページの「BULK COLLECT 句を使用した、問合せ結果のコレクションへの取出し」を参照)。次の例では、1 つのカーソルから 2 つのコレクションにバルク・フェッチを行っています。

DECLARE TYPE NumTab IS TABLE OF employees.employee_id%TYPE; TYPE NameTab IS TABLE OF employees.last_name%TYPE; nums NumTab; names NameTab; CURSOR c1 IS SELECT employee_id, last_name FROM employees WHERE job_id = 'ST_CLERK';BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO nums, names;-- Here is where you iterate through the elements in the NUMS and-- NAMES collections. NULL; CLOSE c1;END;/

カーソルのクローズカーソルのクローズカーソルのクローズカーソルのクローズCLOSE文によってカーソルは使用禁止になり、結果セットは未定義になります。クローズされたカーソルは、再オープンできます。これによって、WHERE句で参照されたカーソル・パラメータおよび変数の 新の値を使用して、問合せが再度実行されます。クローズされたカーソルに対してこれ以外の操作を実行すると、事前定義の例外 INVALID_CURSORが呼び出されます。

PL/SQL での SQL 操作の実行 6-17

Page 206: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

副問合せの使用

副問合せの使用副問合せの使用副問合せの使用副問合せの使用副問合せ副問合せ副問合せ副問合せは、別の SQL DML 文内に出現する問合せであり、多くの場合カッコで囲まれています。文は、副問合せで戻された 1 つの値または複数の値の集合に対して実行されます。次に例を示します。

� 副問合せを使用して列の MAX()、MIN() または AVG() の値を検索し、この単一の値を使用して WHERE 句の中で比較を行うことができます。

� 副問合せを使用して値の集合を検索し、その値を使用して WHERE 句の中で IN またはNOT IN の比較を行うことができます。この方法を使用すると、結合を回避できます。

� 副問合せを使用して値の集合をフィルタリングし、外部の問合せで ORDER BY やGROUP BY などの別の操作を適用できます。

� 問合せの FROM 句で、表名のかわりに副問合せを使用できます。この方法を使用すると、表全体を結合するかわりに、表と別の表から取り出した小さい行セットを結合できます。

� 副問合せで定義した行セットを使用して、表を作成したり、表へ挿入することができます。

DECLARE CURSOR c1 IS-- The main query returns only rows where the salary is greater than the average salary. SELECT employee_id, last_name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);

CURSOR c2 IS-- The subquery returns all the rows in descending order of salary.-- The main query returns just the top 10 highest-paid employees. SELECT * FROM (SELECT last_name, salary FROM employees ORDER BY salary DESC, last_name) WHERE ROWNUM < 11;BEGIN FOR person IN c1 LOOP dbms_output.put_line('Above-average salary: ' || person.last_name); END LOOP; FOR person IN c2 LOOP dbms_output.put_line('Highest paid: ' || person.last_name || ' $' || person.salary); END LOOP;-- The subquery identifies a set of rows to use with CREATE TABLE or INSERT. EXECUTE IMMEDIATE 'CREATE TABLE temp AS (SELECT * FROM employees WHERE salary > 5000)'; EXECUTE IMMEDIATE 'DROP TABLE temp';END;/

6-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 207: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

相関副問合せの使用

FROM句の中で副問合せを使用した次の問合せは、従業員 5 人以上の部門の番号と名称を戻します。

DECLARE CURSOR c1 IS SELECT t1.department_id, department_name, staff FROM departments t1, ( SELECT department_id, COUNT(*) as staff FROM employees GROUP BY department_id ) t2 WHERE t1.department_id = t2.department_id AND staff >= 5;BEGIN FOR dept IN c1 LOOP dbms_output.put_line('Department = ' || dept.department_name || ', staff = ' || dept.staff); END LOOP;END;/

相関副問合せの使用相関副問合せの使用相関副問合せの使用相関副問合せの使用副問合せが各表につき 1 回しか評価されないのに対し、相関副問合せ相関副問合せ相関副問合せ相関副問合せは各行につき 1 回評価されます。次の例では、給与が部門平均を上回っている従業員の名前と給与を戻しています。相関副問合せでは、表の各行について、対応する部門の平均給与を計算します。

DECLARE-- For each department, we find the average salary.-- Then we find all the employees in that department making-- more than that average salary. CURSOR c1 IS SELECT department_id, last_name, salary FROM employees t WHERE salary > ( SELECT AVG(salary) FROM employees WHERE t.department_id = department_id )

PL/SQL での SQL 操作の実行 6-19

Page 208: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

相関副問合せの使用

ORDER BY department_id;BEGIN FOR person IN c1 LOOP dbms_output.put_line('Making above-average salary = ' || person.last_name); END LOOP;END;/

メンテナンス可能なメンテナンス可能なメンテナンス可能なメンテナンス可能な PL/SQL 問合せの作成問合せの作成問合せの作成問合せの作成ローカル変数を参照するかわりに、パラメータを受け入れるカーソルを宣言し、カーソルをオープンしたときにそれらのパラメータの値を渡すことができます。問合せが通常、特定の値を使用して発行される場合、それらの値をデフォルトとして指定できます。パラメータの値を渡すには、位置表記法および名前表記法のいずれも使用できます。

例例例例 6-1 カーソルカーソルカーソルカーソル FOR ループへのパラメータの引渡しループへのパラメータの引渡しループへのパラメータの引渡しループへのパラメータの引渡し

次の例では、指定した部門の従業員に支払われている賃金の合計を計算しています。

DECLARE CURSOR c1 (name VARCHAR2, max_wage NUMBER) IS SELECT * FROM employees WHERE last_name = name and salary < max_wage;BEGIN FOR person IN c1('Austin', 30000) LOOP -- process data record dbms_output.put_line('Name = ' || person.last_name || ', salary = ' || person.salary); END LOOP;END;/

例例例例 6-2 明示カーソルへのパラメータの引渡し明示カーソルへのパラメータの引渡し明示カーソルへのパラメータの引渡し明示カーソルへのパラメータの引渡し

カーソルをオープンする方法の例を次に示します。

DECLARE emp_name employees.last_name%TYPE := 'Austin'; emp_salary employees.salary%TYPE := 30000; my_record employees%ROWTYPE; CURSOR c1 (name VARCHAR2, max_wage NUMBER) IS SELECT * FROM employees WHERE last_name = name and salary < max_wage;BEGIN-- Any of the following statements opens the cursor:

6-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 209: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性の使用

-- OPEN c1('Austin', 3000);-- OPEN c1('Austin', emp_salary);-- OPEN c1(emp_name, 3000);-- OPEN c1(emp_name, emp_salary);

OPEN c1(emp_name, emp_salary); LOOP FETCH c1 INTO my_record; EXIT WHEN c1%NOTFOUND; -- process data record dbms_output.put_line('Name = ' || my_record.last_name || ', salary = ' || my_record.salary); END LOOP;END;/

混同を避けるために、カーソルのパラメータとそれらのパラメータに渡す PL/SQL 変数には異なる名前を使用します。

デフォルト値で宣言された仮パラメータには、対応する実パラメータがなくてもかまいません。実パラメータを省略した場合、仮パラメータは、OPEN文の実行時にデフォルト値を取ります。

カーソル属性の使用カーソル属性の使用カーソル属性の使用カーソル属性の使用どの明示カーソルおよびカーソル変数にも %FOUND、%ISOPEN、%NOTFOUNDおよび%ROWCOUNTの 4 つの属性があります。これらの属性をカーソルまたはカーソル変数に付加すると、DML 文の実行について役立つ情報が戻されます。カーソル属性は、プロシージャ文では使用できますが、SQL 文では使用できません。

明示カーソルの属性の概要明示カーソルの属性の概要明示カーソルの属性の概要明示カーソルの属性の概要明示カーソルの属性は、複数行の問合せの実行に関する情報を戻します。明示カーソルまたはカーソル変数をオープンすると、対応する問合せを満たす行が識別され、結果セットが形成されます。行は、結果セットから取り出されます。

%FOUND カーソル属性カーソル属性カーソル属性カーソル属性 : 1 行がフェッチされたかどうか行がフェッチされたかどうか行がフェッチされたかどうか行がフェッチされたかどうかカーソルまたはカーソル変数のオープン後、 初のフェッチが実行されるまでは、%FOUNDは NULLを戻します。フェッチが実行された後、直前のフェッチが行を戻した場合は TRUEを、直前のフェッチが行を戻さなかった場合は FALSEを戻します。次の例では、%FOUNDを使用して、アクションを選択しています。

PL/SQL での SQL 操作の実行 6-21

Page 210: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性の使用

DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; my_ename employees.last_name%TYPE; my_salary employees.salary%TYPE;BEGIN OPEN c1; LOOP FETCH c1 INTO my_ename, my_salary; IF c1%FOUND THEN -- fetch succeeded dbms_output.put_line('Name = ' || my_ename || ', salary = ' || my_salary); ELSE -- fetch failed, so exit loop EXIT; END IF; END LOOP;END;/

カーソルまたはカーソル変数をオープンしていない場合、%FOUNDでカーソルまたはカーソル変数を参照すると、事前定義の例外 INVALID_CURSORが呼び出されます。

%ISOPEN カーソル属性カーソル属性カーソル属性カーソル属性 : カーソルがオープンしているかどうかカーソルがオープンしているかどうかカーソルがオープンしているかどうかカーソルがオープンしているかどうか%ISOPENは、カーソルまたはカーソル変数をオープンしている場合は TRUEを、他の場合は FALSEを戻します。次の例では、%ISOPENを使用して、アクションを選択しています。

DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; the_name employees.last_name%TYPE; the_salary employees.salary%TYPE;BEGIN IF c1%ISOPEN = FALSE THEN -- cursor was not already open OPEN c1; END IF; FETCH c1 INTO the_name, the_salary; CLOSE c1;END;/

6-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 211: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性の使用

%NOTFOUND カーソル属性カーソル属性カーソル属性カーソル属性 : フェッチが失敗したかどうかフェッチが失敗したかどうかフェッチが失敗したかどうかフェッチが失敗したかどうか%NOTFOUNDは、論理的に %FOUNDの逆です。%NOTFOUNDは、直前の取出しが行を戻した場合は FALSEに、直前の取出しが行を戻さなかった場合は TRUEになります。次の例では、%NOTFOUNDを使用して、FETCHが行を戻さなくなった場合に、ループが終了するようにしています。

DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; my_ename employees.last_name%TYPE; my_salary employees.salary%TYPE;BEGIN OPEN c1; LOOP FETCH c1 INTO my_ename, my_salary; IF c1%NOTFOUND THEN -- fetch failed, so exit loop-- A shorter form of this test is "EXIT WHEN c1%NOTFOUND;" EXIT; ELSE -- fetch succeeded dbms_output.put_line('Name = ' || my_ename || ', salary = ' || my_salary); END IF; END LOOP;END;/

初のフェッチの前は、%NOTFOUNDは NULLを戻します。FETCHが正常に実行されない場合、EXIT WHEN文は WHEN条件が TRUE の場合にのみ実行されるため、ループは終了しません。安全のために、次の EXIT文をかわりに使用できます。

EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;

カーソルまたはカーソル変数をオープンしていない場合、%NOTFOUNDでカーソルまたはカーソル変数を参照すると、例外 INVALID_CURSORが呼び出されます。

%ROWCOUNT カーソル属性カーソル属性カーソル属性カーソル属性 : これまでにフェッチされた行数これまでにフェッチされた行数これまでにフェッチされた行数これまでにフェッチされた行数カーソルまたはカーソル変数をオープンしている場合、%ROWCOUNTは 0(ゼロ)になります。 初のフェッチの前は、%ROWCOUNTの評価結果は 0です。その後は、これまでにフェッチした行の数になります。フェッチで行が戻されるたびに、数値が増えていきます。次の例では、%ROWCOUNTを使用して、フェッチされた行が 10 行を超えたかどうかをテストしています。

DECLARE CURSOR c1 IS SELECT last_name FROM employees WHERE ROWNUM < 11; name employees.last_name%TYPE;BEGIN OPEN c1;

PL/SQL での SQL 操作の実行 6-23

Page 212: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性の使用

LOOP FETCH c1 INTO name; EXIT WHEN c1%NOTFOUND; dbms_output.put_line(c1%ROWCOUNT || '. ' || name); IF c1%ROWCOUNT = 5 THEN dbms_output.put_line('--- Fetched 5th record ---'); END IF; END LOOP; CLOSE c1;END;/

カーソルまたはカーソル変数をオープンしていない場合、%ROWCOUNTでカーソルまたはカーソル変数を参照すると、INVALID_CURSORが呼び出されます。

表 6-1 に、OPEN文、FETCH文または CLOSE文を実行する前後での、各カーソル属性が戻す値を示します。

表表表表 6-1 カーソル属性値カーソル属性値カーソル属性値カーソル属性値

%FOUND %ISOPEN %NOTFOUND %ROWCOUNT

OPEN 前 例外 FALSE 例外 例外

後 NULL TRUE NULL 0

初の FETCH 前 NULL TRUE NULL 0

後 TRUE TRUE FALSE 1

以降の FETCH 前 TRUE TRUE FALSE 1

後 TRUE TRUE FALSE データに依存

後の FETCH 前 TRUE TRUE FALSE データに依存

後 FALSE TRUE TRUE データに依存

CLOSE 前 FALSE TRUE TRUE データに依存

後 例外 FALSE 例外 例外

注意注意注意注意 :

1. カーソルをオープンする前またはカーソルをクローズした後で、%FOUND、%NOTFOUNDまたは %ROWCOUNTを参照すると、INVALID_CURSORが呼び出されます。

2. 初の FETCHの後、結果セットが空の場合、%FOUNDは FALSE、%NOTFOUNDは TRUE、%ROWCOUNTは 0 になります。

6-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 213: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

カーソル変数(カーソル変数(カーソル変数(カーソル変数(REF CURSOR)の使用)の使用)の使用)の使用カーソルと同じように、カーソル変数は複数行の問合せの結果セットの中の現在行を指します。カーソル変数は、特定の問合せと結合されないため、より柔軟性があります。カーソル変数は、正しい列セットを戻す任意の問合せに対してオープンできます。

カーソル変数は、パラメータとしてローカル・サブプログラムおよびストアド・サブプログラムに渡します。1 つのサブプログラム内でカーソル変数をオープンし、別のサブプログラム内でこの変数を処理することで、データ検索を集中的に実行できます。この方法は、PL/SQL サブプログラムが別の言語で記述されたサブプログラムへ結果セットを戻す可能性がある、複数言語のアプリケーションでも役立ちます。

カーソル変数は、すべての PL/SQL クライアントで使用します。たとえば、OCI や Pro*Cプログラムなどの PL/SQL ホスト環境の中でカーソル変数を宣言し、それを入力ホスト変数

(バインド変数)として PL/SQL に渡すことができます。PL/SQL エンジンを備えた Oracle Forms や Oracle Reports などのアプリケーション開発ツールでは、クライアント側でカーソル変数を完全に使用できます。また、クライアントとデータベース・サーバーの間で、リモート・プロシージャ・コールを介してカーソル変数をやり取りできます。

カーソル変数(カーソル変数(カーソル変数(カーソル変数(REF CURSOR))))カーソル変数は、結果セットへのポインタに類似しています。1 つのサブプログラム内で問合せを実行する際にカーソル変数を使用して、問合せ結果を別のサブプログラム(別の言語で記述されている場合もある)で処理します。カーソル変数のデータ型は REF CURSORであり、通称で REF CURSOR と呼ばれます。

常に同じ問合せ作業領域を参照する明示カーソルとは異なり、カーソル変数は異なる作業領域を参照できます。カーソルを使用する予定の場所では、カーソル変数を使用できません。逆の場合も同じです。

変数を使用する理由変数を使用する理由変数を使用する理由変数を使用する理由カーソル変数は、PL/SQL のストアド・サブプログラムと様々なクライアントとの間で問合せの結果セットを渡すために使用します。PL/SQL とそのクライアントは、結果セットが格納されている問合せ作業領域を指すポインタを共有します。たとえば、OCI クライアント、Oracle Forms アプリケーションおよび Oracle データベース・サーバーがすべて同じ作業領域を参照する可能性があります。

カーソル変数の値は、1 つの有効範囲から別の有効範囲に渡すことができるため、問合せ作業領域は、それを指すカーソル変数が存在するかぎりアクセス可能になります。たとえば、Pro*C プログラムに組み込まれた PL/SQL ブロックにホスト・カーソル変数を渡す場合、カーソル変数が指す作業領域は、そのブロックの終了後もアクセス可能な状態のままです。

PL/SQL での SQL 操作の実行 6-25

Page 214: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

クライアント側に PL/SQL エンジンがあれば、クライアントからサーバーへのコールに課される制限はありません。たとえば、クライアント側でカーソル変数を宣言し、それをサーバー側でオープンしてフェッチした後で、クライアント側で引き続きフェッチすることができます。また、PL/SQL ブロックを使用して複数のホスト・カーソル変数を 1 回の往復でオープンまたはクローズすることで、ネットワークの通信量を削減できます。

REF CURSOR 型およびカーソル変数の宣言型およびカーソル変数の宣言型およびカーソル変数の宣言型およびカーソル変数の宣言カーソル変数を作成するには、REF CURSOR型を定義してから、その型のカーソル変数を宣言します。REF CURSOR型は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの中で定義できます。次の例では、DEPARTMENTS表から取り出した結果セットを表す REF CURSOR型を宣言しています。

DECLARE TYPE DeptCurTyp IS REF CURSOR RETURN departments%ROWTYPE;

REF CURSOR型には、強い(戻り型を持つ)ものと弱い(戻り型を持たない)ものがあります。

強い REF CURSOR型の方が、エラー発生の可能性は少なくなります。これは、PL/SQL コンパイラの場合、強い型指定のカーソル変数は正しい列セットを戻す問合せにのみ関連付けることができるためです。弱い REF CURSOR型は、より柔軟です。弱い型指定のカーソル変数は、どの問合せにも関連付けることができます。

弱い REF CURSORに対しては、型のチェックが行われないため、すべての弱い型は互換性があります。新しい型を作成するかわりに、事前定義の SYS_REFCURSOR型を使用することもできます。

REF CURSOR型を宣言すると、PL/SQL ブロックまたはサブプログラムで、その型のカーソル変数を宣言できます。

DECLARE TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; -- strong TYPE GenericCurTyp IS REF CURSOR; -- weak cursor1 EmpCurTyp; cursor2 GenericCurTyp; my_cursor SYS_REFCURSOR; -- didn't need to declare a new type above

次の例では、カーソル変数 dept_cvを宣言しています。

DECLARE TYPE DeptCurTyp IS REF CURSOR RETURN dept%ROWTYPE; dept_cv DeptCurTyp; -- declare cursor variable

REF CURSOR型を使用する各サブプログラムでその同じ型を宣言することを回避するために、パッケージ仕様部で REF CURSORを宣言できます。その型のカーソル変数は、対応するパッケージ本文、または独自のファンクションやプロシージャ内で宣言できます。

6-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 215: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

例例例例 6-3 %ROWTYPE を戻すカーソル変数を戻すカーソル変数を戻すカーソル変数を戻すカーソル変数

REF CURSOR型定義の RETURN句では、%ROWTYPEを使用して、強い型指定のカーソル変数を参照できます。

DECLARE TYPE TmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; tmp_cv TmpCurTyp; -- declare cursor variable TYPE EmpCurTyp IS REF CURSOR RETURN tmp_cv%ROWTYPE; emp_cv EmpCurTyp; -- declare cursor variableBEGIN NULL;END;/

例例例例 6-4 %TYPE を戻すカーソル変数を戻すカーソル変数を戻すカーソル変数を戻すカーソル変数

%TYPEを使用して、レコード変数のデータ型を与えることもできます。

DECLARE dept_rec departments%ROWTYPE; -- declare record variable TYPE DeptCurTyp IS REF CURSOR RETURN dept_rec%TYPE; dept_cv DeptCurTyp; -- declare cursor variableBEGIN NULL;END;/

例例例例 6-5 レコード型を戻すカーソル変数レコード型を戻すカーソル変数レコード型を戻すカーソル変数レコード型を戻すカーソル変数

次の例では、RETURN句の中でユーザー定義の RECORD型を指定しています。

DECLARE TYPE EmpRecTyp IS RECORD ( employee_id NUMBER, last_name VARCHAR2(30), salary NUMBER(7,2)); TYPE EmpCurTyp IS REF CURSOR RETURN EmpRecTyp; emp_cv EmpCurTyp; -- declare cursor variableBEGIN NULL;END;/

PL/SQL での SQL 操作の実行 6-27

Page 216: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

パラメータとしてのカーソル変数の引渡しパラメータとしてのカーソル変数の引渡しパラメータとしてのカーソル変数の引渡しパラメータとしてのカーソル変数の引渡しカーソル変数をファンクションおよびプロシージャの仮パラメータとして宣言できます。次の例では、REF CURSOR型を定義し、その型のカーソル変数を仮パラメータとして宣言しています。

DECLARE TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; emp EmpCurTyp;

-- Once we have a result set, we can process all the rows-- inside a single procedure rather than calling a procedure-- for each row. PROCEDURE process_emp_cv (emp_cv IN EmpCurTyp) IS person employees%ROWTYPE; BEGIN dbms_output.put_line('-----'); dbms_output.put_line('Here are the names from the result set:'); LOOP FETCH emp_cv INTO person; EXIT WHEN emp_cv%NOTFOUND; dbms_output.put_line('Name = ' || person.first_name || ' ' || person.last_name); END LOOP; END;

BEGIN-- First find 10 arbitrary employees. OPEN emp FOR SELECT * FROM employees WHERE ROWNUM < 11; process_emp_cv(emp); CLOSE emp;-- Then find employees matching a condition. OPEN emp FOR SELECT * FROM employees WHERE last_name LIKE 'R%'; process_emp_cv(emp); CLOSE emp;END;/

注意注意注意注意 : すべてのポインタと同様に、カーソル変数にはパラメータのエイリアシングの可能性があります。8-12 ページの「サブプログラム名のオーバーロード」を参照してください。

カーソル変数の制御カーソル変数の制御カーソル変数の制御カーソル変数の制御 : OPEN-FOR、、、、FETCH およびおよびおよびおよび CLOSEカーソル変数の制御には、OPEN-FOR、FETCHおよび CLOSEの 3 つの文を使用します。まず、OPEN-FOR文でカーソル変数を複数行問合せ用にオープンします。次に、FETCH文で結果セットから行を取り出します。すべての行が処理された後に、CLOSE文でカーソル変数をクローズします。

6-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 217: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

カーソル変数のオープンカーソル変数のオープンカーソル変数のオープンカーソル変数のオープンOPEN-FOR文を使用すると、カーソル変数を複数行の問合せに結び付けたり、問合せを実行したり、結果セットを識別することができます。

OPEN {cursor_variable | :host_cursor_variable} FOR{ select_statement | dynamic_string [USING bind_argument[, bind_argument]...] };

カーソル変数は、PL/SQL 内、または OCI プログラムなどの PL/SQL ホスト環境で直接宣言できます。

問合せの SELECT文は、文中に直接コーディングすることも、文字列変数または文字列リテラルにすることもできます。文字列を問合せとして使用する場合、文字列にバインド変数用のプレースホルダを含め、USING 句を使用して対応する値を指定できます。

注意注意注意注意 : この項では静的 SQL の場合について説明します。ここでは select_statementを使用します。動的 SQL の場合は dynamic_stringが使用されます。13-129 ページの

「OPEN-FOR-USING 文」を参照してください。

カーソルとは異なり、カーソル変数はパラメータを取りません。かわりに、カーソル変数にはパラメータのみでなく問合せ全体を渡すことができます。問合せでは、ホスト変数、PL/SQL 変数、パラメータおよびファンクションを参照できます。

次に示す例では、カーソル変数をオープンしています。カーソルの属性(%FOUND、%NOTFOUND、%ISOPEN、%ROWCOUNT)をカーソル変数に適用できることに注意してください。

DECLARE TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; emp_cv EmpCurTyp;BEGIN IF NOT emp_cv%ISOPEN THEN /* Open cursor variable. */ OPEN emp_cv FOR SELECT * FROM employees; END IF; CLOSE emp_cv;END;/

その他の OPEN-FOR文は、異なる複数の問合せ用に同じカーソル変数をオープンできます。カーソル変数を再オープンする場合、その前にクローズする必要はありません。(静的カーソルを OPEN文で連続してオープンすると、事前定義の例外 CURSOR_ALREADY_OPENが呼び出されます。)別の問合せ用にカーソル変数を再オープンすると、前の問合せは失われます。

PL/SQL での SQL 操作の実行 6-29

Page 218: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

例例例例 6-6 REF CURSOR をオープンするストアド・プロシージャをオープンするストアド・プロシージャをオープンするストアド・プロシージャをオープンするストアド・プロシージャ

一般に、カーソル変数をオープンするときは、カーソル変数である IN OUT パラメータを宣言するストアド・プロシージャにそのカーソル変数を渡します。たとえば、次のプロシージャは、カーソル変数をオープンします。

CREATE PACKAGE emp_data AS TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp);END emp_data;/

CREATE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp) IS BEGIN OPEN emp_cv FOR SELECT * FROM employees; END open_emp_cv;END emp_data;/

DROP PACKAGE emp_data;

スタンドアロン・ストアド・プロシージャを使用してカーソル変数をオープンする方法もあります。パッケージの中で REF CURSOR型を定義して、ストアド・プロシージャのパラメータ宣言でその型を参照します。

例例例例 6-7 別の問合せで別の問合せで別の問合せで別の問合せで REF CURSOR をオープンするストアド・プロシージャをオープンするストアド・プロシージャをオープンするストアド・プロシージャをオープンするストアド・プロシージャ

データ検索を集中的に実行するために、ストアド・プロシージャの中で型互換性のある問合せをグループにまとめることができます。次に示す例では、パッケージ・プロシージャは仮パラメータの 1 つとして選択子を宣言しています。コールされた場合、プロシージャは選択された問合せに対してカーソル変数 emp_cvをオープンします。

CREATE PACKAGE emp_data AS TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice INT);END emp_data;

CREATE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice INT) IS BEGIN IF choice = 1 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE comm IS NOT NULL; ELSIF choice = 2 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE sal > 2500; ELSIF choice = 3 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE deptno = 20; END IF;

6-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 219: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

END;END emp_data;

例例例例 6-8 異なる戻り型を持つカーソル変数異なる戻り型を持つカーソル変数異なる戻り型を持つカーソル変数異なる戻り型を持つカーソル変数

さらに柔軟性を高めるために、異なる戻り型を指定した問合せをストアド・プロシージャで実行できます。

CREATE PACKAGE admin_data AS TYPE GenCurTyp IS REF CURSOR; PROCEDURE open_cv (generic_cv IN OUT GenCurTyp, choice INT);END admin_data;

CREATE PACKAGE BODY admin_data AS PROCEDURE open_cv (generic_cv IN OUT GenCurTyp, choice INT) IS BEGIN IF choice = 1 THEN OPEN generic_cv FOR SELECT * FROM emp; ELSIF choice = 2 THEN OPEN generic_cv FOR SELECT * FROM dept; ELSIF choice = 3 THEN OPEN generic_cv FOR SELECT * FROM salgrade; END IF; END;END admin_data;

ホスト変数としてのカーソル変数の使用ホスト変数としてのカーソル変数の使用ホスト変数としてのカーソル変数の使用ホスト変数としてのカーソル変数の使用OCI や Pro*C プログラムなどの PL/SQL ホスト環境で、カーソル変数を宣言できます。カーソル変数を使用する場合は、ホスト変数として PL/SQL に渡す必要があります。次のPro*C の例では、ホスト・カーソル変数と選択子を PL/SQL ブロックに渡すことで、選択した問合せ用のカーソル変数をオープンしています。

EXEC SQL BEGIN DECLARE SECTION; ... /* Declare host cursor variable. */ SQL_CURSOR generic_cv; int choice;EXEC SQL END DECLARE SECTION;.../* Initialize host cursor variable. */EXEC SQL ALLOCATE :generic_cv;.../* Pass host cursor variable and selector to PL/SQL block. */EXEC SQL EXECUTEBEGIN IF :choice = 1 THEN

PL/SQL での SQL 操作の実行 6-31

Page 220: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

OPEN :generic_cv FOR SELECT * FROM emp; ELSIF :choice = 2 THEN OPEN :generic_cv FOR SELECT * FROM dept; ELSIF :choice = 3 THEN OPEN :generic_cv FOR SELECT * FROM salgrade; END IF;END;END-EXEC;

ホスト・カーソル変数はすべての問合せの戻り型と互換性があります。ホスト・カーソル変数は、弱い型指定の PL/SQL カーソル変数と同じように動作します。

カーソル変数からのフェッチカーソル変数からのフェッチカーソル変数からのフェッチカーソル変数からのフェッチFETCH文は、複数行の問合せの結果セットから、行を取り出します。この文は、カーソル変数を使用しても、明示カーソルを使用した場合と同様に機能します。

例例例例 6-9 カーソル変数からレコードへのフェッチカーソル変数からレコードへのフェッチカーソル変数からレコードへのフェッチカーソル変数からレコードへのフェッチ

次の例では、カーソル変数からレコードへ一度に 1 行ずつ行をフェッチしています。

DECLARE TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; emp_cv EmpCurTyp; emp_rec employees%ROWTYPE;BEGIN OPEN emp_cv FOR SELECT * FROM employees WHERE salary < 3000; LOOP /* Fetch from cursor variable. */ FETCH emp_cv INTO emp_rec; EXIT WHEN emp_cv%NOTFOUND; -- exit when last row is fetched -- process data record dbms_output.put_line('Name = ' || emp_rec.first_name || ' ' || emp_rec.last_name); END LOOP; CLOSE emp_cv;END;/

例例例例 6-10 カーソル変数からコレクションへのフェッチカーソル変数からコレクションへのフェッチカーソル変数からコレクションへのフェッチカーソル変数からコレクションへのフェッチ

BULK COLLECT句を使用して、1 つのカーソル変数から 1 つ以上のコレクションに行のバルク・フェッチを行います。

DECLARE TYPE EmpCurTyp IS REF CURSOR; TYPE NameList IS TABLE OF employees.last_name%TYPE;

6-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 221: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

TYPE SalList IS TABLE OF employees.salary%TYPE; emp_cv EmpCurTyp; names NameList; sals SalList;BEGIN OPEN emp_cv FOR SELECT last_name, salary FROM employees WHERE salary < 3000; FETCH emp_cv BULK COLLECT INTO names, sals; CLOSE emp_cv;-- Now loop through the NAMES and SALS collections. FOR i IN names.FIRST .. names.LAST LOOP dbms_output.put_line('Name = ' || names(i) || ', salary = ' || sals(i)); END LOOP;END;/

カーソル変数がオープンしている場合のみ、対応付けられた問合せの中の変数が評価されます。結果セットや問合せの中の変数の値を変更する場合は、カーソル変数を新しい値に設定して再オープンします。同じカーソル変数を使用して、別々の FETCH 文で、異なる INTO句を使用できます。各 FETCH 文で同じ結果セットから別の行をフェッチします。

PL/SQL では、カーソル変数の戻り型が、必ず FETCH文の INTO句と互換性を持ちます。互換性がない場合、カーソル変数が強い型指定の場合はコンパイル時に、弱い型指定の場合は実行時にエラーが発生します。実行時に、PL/SQL は 初の取出しの前に、事前定義の例外 ROWTYPE_MISMATCHを呼び出します。エラーをトラップし、異なる(互換性のある)INTO句を使用して FETCH文を実行すると、行は失われません。

カーソル変数を、そのカーソル変数から取り出すサブプログラムの仮パラメータとして宣言する場合は、INまたは IN OUTモードを指定する必要があります。サブプログラムがカーソル変数もオープンする場合は、IN OUTモードを指定する必要があります。

クローズしている、または一度もオープンされていないカーソル変数からフェッチを実行すると、PL/SQL によって事前定義の例外 INVALID_CURSORが呼び出されます。

カーソル変数のクローズカーソル変数のクローズカーソル変数のクローズカーソル変数のクローズCLOSE文によってカーソル変数は使用禁止になり、関連する結果セットは未定義になります。 後の行が処理された後でカーソル変数をクローズします。

カーソル変数を、そのカーソル変数をクローズするサブプログラムの仮パラメータとして宣言する場合は、INまたは IN OUTモードを指定する必要があります。

すでにクローズされているか、1 度もオープンされたことのないカーソル変数をクローズすると、PL/SQL によって事前定義の例外 INVALID_CURSORが呼び出されます。

PL/SQL での SQL 操作の実行 6-33

Page 222: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数(REF CURSOR)の使用

ホスト・カーソル変数をホスト・カーソル変数をホスト・カーソル変数をホスト・カーソル変数を PL/SQL に渡すときのネットワークの通信量の削減に渡すときのネットワークの通信量の削減に渡すときのネットワークの通信量の削減に渡すときのネットワークの通信量の削減ホスト・カーソル変数を PL/SQL に渡す場合、OPEN-FOR文をグループ化することでネットワークの通信量を削減できます。たとえば、次の PL/SQL ブロックでは、1 回の往復で複数のカーソル変数をオープンします。

/* anonymous PL/SQL block in host environment */ BEGIN OPEN :emp_cv FOR SELECT * FROM employees; OPEN :dept_cv FOR SELECT * FROM departments; OPEN :loc_cv FOR SELECT * FROM locations; END;

この方法は Oracle Forms で便利です(たとえば、マルチブロック・フォームにデータを入れる場合)。

ホスト・カーソル変数を PL/SQL ブロックに渡してオープンする場合、ホスト・カーソル変数が指す問合せ作業領域は、ブロックの終了後もアクセス可能な状態のままです。そのため、OCI や Pro*C プログラムで、通常のカーソル操作用にその作業領域を使用できます。次の例では、1 回の往復でこのような作業領域をいくつかオープンします。

BEGIN OPEN :c1 FOR SELECT 1 FROM dual; OPEN :c2 FOR SELECT 1 FROM dual; OPEN :c3 FOR SELECT 1 FROM dual;END;

c1、c2および c3に代入されたカーソルは通常どおり動作し、あらゆる用途に使用できます。終了すると、次のようにカーソルを解放します。

BEGIN CLOSE :c1; CLOSE :c2; CLOSE :c3;END;

カーソル変数でのエラーの回避カーソル変数でのエラーの回避カーソル変数でのエラーの回避カーソル変数でのエラーの回避代入に関係する両方のカーソル変数が強い型指定である場合は、両方が同じデータ型であることが必要です(同じ戻り型であるのみでは不十分です)。一方または両方のカーソル変数が弱い型指定である場合は、データ型が異なってもかまいません。

問合せ作業領域を指していないカーソル変数に対して取出しまたはクローズを実行するか、カーソルの属性を参照すると、PL/SQL によって例外 INVALID_CURSORが呼び出されます。カーソル変数(またはパラメータ)が問合せ作業領域を指すようにするには、次の 2 通りの方法があります。

� OPEN-FOR文でカーソル変数を問合せ用にオープンします。

6-34 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 223: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル式の使用

� OPEN文ですでにオープンされたホスト・カーソル変数または PL/SQL カーソル変数の値を、カーソル変数に代入します。

オープンされていないカーソル変数を別のカーソル変数に代入すると、1 番目のカーソル変数をオープンした後も、2 番目のカーソル変数は無効のままです。

カーソル変数をパラメータとして渡す場合は注意が必要です。実パラメータと仮パラメータの戻り型に互換性がないと、実行時に PL/SQL によって ROWTYPE_MISMATCHが呼び出されます。

カーソル変数の制限カーソル変数の制限カーソル変数の制限カーソル変数の制限現在、カーソル変数には次の制限があります。

� パッケージ仕様部ではカーソル変数を宣言できません。たとえば、次の宣言は誤りです。

CREATE PACKAGE emp_stuff AS TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; emp_cv EmpCurTyp; -- not allowedEND emp_stuff;

� データベース・リンクを介してコールされたプロシージャにカーソル変数を渡すことはできません。

� ホスト・カーソル変数を PL/SQL に渡す場合は、同じサーバー・コールで変数をオープンしないかぎり、サーバー側で変数からフェッチできません。

� 比較演算子を使用して、カーソル変数が等しいかどうか、または NULL かどうかをテストできません。

� NULL をカーソル変数に代入できません。

� データベースの列にカーソル変数の値を格納できません。CREATE TABLE文の中で使用するための等価の型は存在しません。

� カーソル変数を、結合配列、ネストした表または VARRAY に格納できません。

� カーソルとカーソル変数には相互操作性がありません。つまり、一方の値が期待されている場所で、もう一方が使用できません。たとえば、カーソル FORループの中ではカーソル変数を参照できません。

カーソル式の使用カーソル式の使用カーソル式の使用カーソル式の使用カーソル式はネストしたカーソルを戻します。結果セットの各行には、通常の値の他に、行内の他の値に関係する副問合せで生成されるカーソルも含まれることがあります。1 つの問合せで、複数の表から取り出された関連値の大きな集合を戻すことができます。結果セットは、 初にその行から、次に各行でネストしたカーソルからフェッチするネステッド・ループで処理できます。

PL/SQL での SQL 操作の実行 6-35

Page 224: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル式の使用

PL/SQL では、カーソルの宣言、REF CURSORの宣言および REF CURSOR 変数の一部として、カーソル式を持つ問合せがサポートされます。また、カーソル式は動的 SQL 問合せにも使用できます。次に構文を示します。

CURSOR(subquery)

ネストしたカーソルは、それを含んでいる行が親カーソルからフェッチされるときに暗黙的にオープンされます。ネストしたカーソルがクローズされるのは、次の場合のみです。

� ネストしたカーソルをユーザーが明示的にクローズしたとき。

� 親カーソルが再実行されるとき。

� 親カーソルがクローズされるとき。

� 親カーソルが取り消されるとき。

� 親カーソルの 1 つのフェッチ中にエラーが呼び出されるとき。ネストしたカーソルはクリーンアップの一部としてクローズされます。

カーソル式の制限カーソル式の制限カーソル式の制限カーソル式の制限� カーソル式は、暗黙カーソルとは併用できません。

� カーソル式を使用できるのは、次の場合のみです。

� カーソル式自体が副問合せである場合を除き、他の問合せの式の中でネストされていない SELECT文中。

� SELECT文の FROM句で、テーブル・ファンクションの引数として。

� カーソル式を使用できるのは、問合せ仕様部の も外側の SELECTリスト内のみです。

� カーソル式はビュー宣言には使用できません。

� カーソル式の BINDおよび EXECUTE操作は実行できません。

カーソル式の例カーソル式の例カーソル式の例カーソル式の例この例では、指定した所在地 ID と、その所在地にある全部門をフェッチできるカーソルを検索します。各部門の名前をフェッチすると、別の表から関連する従業員詳細をフェッチできる、もう 1 つのカーソルも取得します。

DECLARE TYPE emp_cur_typ IS REF CURSOR; emp_cur emp_cur_typ; dept_name departments.department_name%TYPE; emp_name employees.last_name%TYPE; CURSOR c1 IS SELECT department_name,-- The 2nd item in the result set is another result set,

6-36 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 225: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル式の使用

-- which is represented as a ref cursor and labelled "employees". CURSOR ( SELECT e.last_name FROM employees e WHERE e.department_id = d.department_id ) employees FROM departments d WHERE department_name like 'A%';

BEGIN OPEN c1; LOOP FETCH c1 INTO dept_name, emp_cur; EXIT WHEN c1%NOTFOUND; dbms_output.put_line('Department: ' || dept_name);-- For each row in the result set, we can process the result-- set from a subquery. We could pass the ref cursor to a procedure-- instead of processing it here in the loop. LOOP FETCH emp_cur INTO emp_name; EXIT WHEN emp_cur%NOTFOUND; dbms_output.put_line(' Employee: ' || emp_name); END LOOP; END LOOP; CLOSE c1;END;/

カーソル副問合せを使用したカーソル副問合せを使用したカーソル副問合せを使用したカーソル副問合せを使用した REF CURSOR の構成の構成の構成の構成カーソル副問合せはカーソル式とも呼ばれ、ファンクションにパラメータとして行セットを渡すことができます。たとえば、次の文では、StockPivot ファンクションにパラメータを渡しており、このファンクションはカーソル副問合せから戻される行を表す REF CURSORで構成されています。

SELECT * FROM TABLE(StockPivot(CURSOR(SELECT * FROM StockTable)));

カーソル副問合せは、通常はテーブル・ファンクションと併用されます。11-36 ページの「テーブル・ファンクションでの変換パイプラインの設定」を参照してください。

PL/SQL での SQL 操作の実行 6-37

Page 226: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

PL/SQL におけるトランザクション処理の概要におけるトランザクション処理の概要におけるトランザクション処理の概要におけるトランザクション処理の概要この項では、PL/SQL を使用したトランザクション処理の方法を説明します。

事前に、トランザクションの概要を理解し、COMMIT文、SAVEPOINT文、ROLLBACK文などのデータベースの一貫性を保証する方法を理解しておく必要があります。これらは Oracleの機能で、すべてのプログラミング言語で使用できます。これらの機能によって、複数のユーザーがデータベース上で同時に作業できます。また、各ユーザーが参照するデータのバージョンに一貫性があり、すべての変更が正しい順序で適用されることが保証されます。

通常、複数のユーザーがデータに同時にアクセスすることによって発生する問題を防ぐために、追加のコードを記述する必要はありません。Oracle では、ロックロックロックロックを使用してデータへの同時アクセスを制御します。Oracle は、必要 小限のデータのみを、できるかぎり短い時間ロックします。表または行のロックは、どうしてもこのレベルの制御が必要な場合に要求できます。行の共有行の共有行の共有行の共有および排他排他排他排他のような数種類のロッキングのモードモードモードモードから選択できます。

PL/SQL でのでのでのでの COMMIT、、、、SAVEPOINT およびおよびおよびおよび ROLLBACK の使用の使用の使用の使用COMMIT文、SAVEPOINT文および ROLLBACK文は、PL/SQL プログラム内に直接含めることができます。

COMMIT文は、カレント・トランザクションを終了し、トランザクション中に加えられた変更を永続的なものにして、他のユーザーから参照できるようにします。

ROLLBACK文は、カレント・トランザクションを終了し、トランザクション中に加えられたすべての変更を取り消します。表から間違った行の削除などご操作を行った場合に、ロールバックは元のデータをリストアできます。例外が呼び出されたり SQL 文が失敗したためにトランザクションを終了できない場合は、ロールバックを使用すると、対処措置を行い、実行しなおすことができます。

SAVEPOINTは、トランザクション処理内の現在位置に名前とマークを付けます。セーブポイントを使用すると、トランザクション全体をロールバックするのではなく、トランザクションの一部をロールバックできます。

銀行口座の間で振替えを実行するトランザクションを考えます。一方の口座から現金が出金され、同時に他方の口座に現金が入金されることが重要です。そうでない場合、処理の途中で問題が発生すると、両方の口座からその金額の現金が消失したり、両方の口座でその金額の現金が重複する可能性があります。

BEGIN UPDATE accts SET bal = my_bal - debit WHERE acctno = 7715; UPDATE accts SET bal = my_bal + credit WHERE acctno = 7720; COMMIT WORK;END;

6-38 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 227: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

トランザクションは、PL/SQL の BEGIN-ENDブロックとは結び付けられません。ブロックは複数のトランザクションを含むことができます。また、トランザクションは複数のブロックにまたがることができます。

オプションの COMMENT句を使用すると、分散トランザクションに対応付けるコメントを指定できます。コミット中にネットワークやマシンに障害が発生した場合、分散トランザクションが認識されないかまたはインダウトの状態になる可能性があります。この場合、Oracle は、COMMENTで指定されたテキストをトランザクション ID とともにデータ・ディクショナリに格納します。テキストは、引用符で囲んだ 50 文字以下のリテラルであることが必要です。

COMMIT COMMENT 'In-doubt order transaction; notify Order Entry';

PL/SQL は、SQL の FORCE句(インダウト分散トランザクションを手動でコミットする句)をサポートしていません。

次の例では、3 つの異なるデータベース表に従業員に関する情報を挿入しています。INSERT文で重複する従業員番号を格納すると、事前定義の例外 DUP_VAL_ON_INDEXが呼び出されます。すべての 3 つの表に対する変更が取り消されたことを確認するために、例外ハンドラが ROLLBACKを実行します。

DECLARE emp_id INTEGER;BEGIN SELECT empno, ... INTO emp_id, ... FROM new_emp WHERE ... INSERT INTO emp VALUES (emp_id, ...); INSERT INTO tax VALUES (emp_id, ...); INSERT INTO pay VALUES (emp_id, ...);EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK;END;

文レベルのロールバック文レベルのロールバック文レベルのロールバック文レベルのロールバックSQL 文を実行する前に、Oracle は暗黙的なセーブポイントをマークします。その文が失敗すると、Oracle は自動的にロールバックします。たとえば、INSERT文で一意の索引に重複する値を挿入しようとしたために例外が呼び出されると、その文はロールバックされます。失われるのは失敗した SQL 文による処理のみです。カレント・トランザクション中のその文以前の処理は、保存されます。

Oracle では、デッドロックを解消するために SQL 文を 1 文のみロールバックすることもできます。Oracle は関係しているトランザクションの 1 つにエラーを戻し、そのトランザクション中の現在の文をロールバックします。

SQL 文を実行する前に、Oracle はその文を解析する必要があります。すなわち、その文が構文規則に従っているかどうかや、有効なスキーマ・オブジェクトを参照しているかどうかを確認する必要があります。SQL 文の実行時に検出されたエラーはロールバックを引き起こしますが、文の解析の際に検出されたエラーはロールバックを引き起こしません。

PL/SQL での SQL 操作の実行 6-39

Page 228: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

次の例では、挿入する前にセーブポイントをマークしています。INSERT文で empno列に重複した値を格納すると、事前定義の例外 DUP_VAL_ON_INDEXが呼び出されます。この場合は、セーブポイントまでロールバックして、その挿入のみを取り消すことができます。

DECLARE emp_id emp.empno%TYPE;BEGIN UPDATE emp SET ... WHERE empno = emp_id; DELETE FROM emp WHERE ... SAVEPOINT do_insert; INSERT INTO emp VALUES (emp_id, ...);EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK TO do_insert;END;

あるセーブポイントまでロールバックすると、そのセーブポイント以降にマークされたセーブポイントはすべて消去されます。ロールバック先のセーブポイントは消去されません。単純なロールバックまたはコミットではすべてのセーブポイントが消去されます。

再帰的サブプログラムの中でセーブポイントをマークすると、再帰しながら進む過程で、各レベルで SAVEPOINT文の新しいインスタンスが実行されます。ただし、ロールバックできるのは直前にマークされたセーブポイントまでです。

セーブポイント名は未宣言の識別子です。セーブポイント名を再利用すると、セーブポイントはトランザクションの中の古い位置から現在の位置に移動します。つまり、セーブポイントへのロールバックは、トランザクションの現在の部分のみに影響を与えます。

BEGIN SAVEPOINT my_point; UPDATE emp SET ... WHERE empno = emp_id; SAVEPOINT my_point; -- move my_point to current point INSERT INTO emp VALUES (emp_id, ...);EXCEPTION WHEN OTHERS THEN ROLLBACK TO my_point;END;

セッションごとのアクティブなセーブポイントの数には、制限がありません。

6-40 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 229: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

Oracle による暗黙的なロールバックの実行方法による暗黙的なロールバックの実行方法による暗黙的なロールバックの実行方法による暗黙的なロールバックの実行方法INSERT文、UPDATE文または DELETE文を実行する前に、Oracle は(ユーザーが利用できない)暗黙的なセーブポイントをマークします。文の実行に失敗すると、Oracle はこのセーブポイントまでロールバックします。通常は、トランザクション全体ではなく、失敗したSQL 文のみがロールバックされます。その文が原因で未処理例外が呼び出された場合は、ホスト環境によってロールバックの対象が決まります。

ストアド・サブプログラムを未処理例外で終了すると、PL/SQL は値を OUTパラメータに代入せず、ロールバックを実行しません。

トランザクションの終了トランザクションの終了トランザクションの終了トランザクションの終了すべてのトランザクションは、明示的にコミットまたはロールバックする必要があります。コミットを発行するか、または PL/SQL プログラムまたはクライアント・プログラムでロールバックするかは、アプリケーション・ロジックによって決まります。トランザクションを明示的にコミットまたはロールバックしなかった場合は、クライアント環境によって 終的な状態が決定されます。

たとえば、SQL*Plus 環境で、PL/SQL ブロックに COMMIT文または ROLLBACK文がない場合、トランザクションの 終状態はそのブロックの実行後に行うことによって決まります。ユーザーがデータ定義文、データ制御文または COMMIT文を実行するか、EXITコマンド、DISCONNECTコマンドまたは QUITコマンドを発行すると、Oracle はトランザクションをコミットします。ROLLBACK文を実行するか SQL*Plus セッションを中断すると、Oracle はトランザクションをロールバックします。

Oracle プリコンパイラ・プログラムは、プログラムで処理を明示的にコミットまたはロールバックしないかぎり、トランザクションをロールバックし、RELEASEパラメータを使用して切断します。

EXEC SQL COMMIT WORK RELEASE;

SET TRANSACTION を使用したトランザクション・プロパティの設定を使用したトランザクション・プロパティの設定を使用したトランザクション・プロパティの設定を使用したトランザクション・プロパティの設定SET TRANSACTION文を使用すると、読取り専用または読取り / 書込みトランザクションの開始、分離レベルの確立、指定したロールバック・セグメントへのカレント・トランザクションの割当てができます。読取り専用トランザクションは、他のユーザーが更新している表に対して複数の問合せを実行する場合に便利です。

読取り専用トランザクションでは、複数の表と複数の問合せで構成された読取り一貫性のあるビューが作成され、すべての問合せがデータベースの同一のスナップショットを参照します。他のユーザーは、通常の方法でデータの問合せや更新ができます。コミットまたはロールバックするとトランザクションが終了します。次の例では、スーパーマーケットの店長が、読取り専用トランザクションを使用して、当日、先週および先月の売上を調べています。トランザクションの途中で他のユーザーがデータベースを更新しても、売上の数値には影響がありません。

PL/SQL での SQL 操作の実行 6-41

Page 230: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

DECLARE daily_sales REAL; weekly_sales REAL; monthly_sales REAL;BEGIN COMMIT; -- ends previous transaction SET TRANSACTION READ ONLY NAME 'Calculate sales figures'; SELECT SUM(amt) INTO daily_sales FROM sales WHERE dte = SYSDATE; SELECT SUM(amt) INTO weekly_sales FROM sales WHERE dte > SYSDATE - 7; SELECT SUM(amt) INTO monthly_sales FROM sales WHERE dte > SYSDATE - 30; COMMIT; -- ends read-only transactionEND;

SET TRANSACTION文は、読取り専用トランザクションの 初の SQL 文である必要があり、1 つのトランザクションで 1 回しか使用できません。トランザクションを READ ONLYに設定すると、それ以降の問合せからはトランザクションの開始前にコミットされた変更内容しか見えません。READ ONLYを使用しても、他のユーザーや他のトランザクションには影響がありません。

SET TRANSACTION の制限の制限の制限の制限読取り専用トランザクションに使用できるのは、SELECT INTO、OPEN、FETCH、CLOSE、LOCK TABLE、COMMITおよび ROLLBACK文のみです。問合せは FOR UPDATEにはできません。

デフォルトのロックの上書きデフォルトのロックの上書きデフォルトのロックの上書きデフォルトのロックの上書きデフォルトで、Oracle はデータ構造を自動的にロックします。これは Oracle データベースの も重要なメリットです。様々なアプリケーションでは、相互のデータに悪影響を与えたりデータを同調させることなく、同じデータの読取りおよび書込みを実行できます。

デフォルトのロックを上書きする必要がある場合は、特定の行や表全体のデータ・ロックを要求できます。明示的なロックによって、トランザクション中の表に対するアクセスを拒否できます。

� LOCK TABLE文を使用すると、明示的に表全体をロックできます。

� SELECT FOR UPDATE文を使用すると、表の特定の行を明示的にロックし、行を読み取った後に行が変更されないようにできます。この方法によって、文を発行する前に、UPDATE 文または DELETE 文が影響を与える行およびその数を確認できます。この間、他のアプリケーションは行を変更できません。

6-42 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 231: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

FOR UPDATE の使用の使用の使用の使用

UPDATE文または DELETE文の CURRENT OF句で参照されるカーソルを宣言する場合は、FOR UPDATE句を使用して排他的な行ロックを取得する必要があります。次に例を示します。

DECLARE CURSOR c1 IS SELECT empno, sal FROM emp WHERE job = 'SALESMAN' AND comm > sal FOR UPDATE NOWAIT;

SELECT ... FOR UPDATE文は、更新または削除する行を識別し、結果セット内の各行をロックします。これは、行の中の既存の値に基づいて更新する場合に便利です。この場合、更新の前に他のユーザーが行を変更しないようにする必要があります。

オプションのキーワード NOWAITを指定すると、Oracle は他のユーザーが要求された行をロックしていても待機しません。制御はただちにプログラムに戻されるため、他の処理を行ってから、改めてロックを試みてください。キーワード NOWAITを省略すると、Oracle は行が利用できるようになるまで待ちます。

カーソルをオープンしたときにすべての行がロックされるのであり、行がフェッチされるときにロックされるのではありません。また、トランザクションをコミットまたはロールバックすると、行のロックは解除されます。行がロックされていないため、コミットの後で FOR UPDATEカーソルからフェッチすることはできません。(回避策の詳細は、6-44 ページの

「コミットにまたがるフェッチ」を参照してください。)

複数の表に対して問合せを実行する場合は、FOR UPDATE句を使用して、ロックを特定の表に制限できます。表の行は、FOR UPDATE OF句でその表の列を参照する場合にのみロックされます。たとえば、次の問合せでは表 empの行はロックされますが、表 deptの行はロックされません。

DECLARE CURSOR c1 IS SELECT ename, dname FROM emp, dept WHERE emp.deptno = dept.deptno AND job = 'MANAGER' FOR UPDATE OF sal;

カーソルからフェッチされた 新の行を参照するには、次に示すように UPDATE文またはDELETE文で CURRENT OF句を使用します。

DECLARE CURSOR c1 IS SELECT empno, job, sal FROM emp FOR UPDATE;BEGIN OPEN c1; LOOP FETCH c1 INTO ... UPDATE emp SET sal = new_sal WHERE CURRENT OF c1; END LOOP;

PL/SQL での SQL 操作の実行 6-43

Page 232: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL におけるトランザクション処理の概要

LOCK TABLE の使用の使用の使用の使用LOCK TABLE文を使用して、指定されたロック・モードでデータベース表全体をロックすると、表へのアクセスを共有または拒否できます。行共有ロックでは表に対する同時アクセスができます。つまり、他のユーザーが排他的使用のために表全体をロックしないようにします。表ロックは、トランザクションがコミットまたはロールバックを発行したときに解除されます。

LOCK TABLE emp IN ROW SHARE MODE NOWAIT;

ロック・モードによって、表に対して他にどのようなロックを使用できるかが決まります。たとえば、1 つの表に対して多くのユーザーが同時に行共用ロックを取得できますが、排他ロックを取得できるのは一度に 1 人のユーザーのみです。あるユーザーが表に対して排他ロックをかけていると、他のユーザーはその表に対して行の挿入、更新、削除を実行できません。ロック・モードの詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

表がロックされていても、他のユーザーは表に対して問合せできますが、問合せを実行しても表のロックを取得できません。2 つの異なるトランザクションが同じ行を変更した場合のみ、一方のトランザクションがもう一方のトランザクションの終了を待ちます。

コミットにまたがるフェッチコミットにまたがるフェッチコミットにまたがるフェッチコミットにまたがるフェッチコミットの後で FOR UPDATEカーソルからのフェッチを試行すると、PL/SQL によって例外が呼び出されます。FOR UPDATE句によって、カーソルをオープンすると行がロックされ、コミットすると行のロックが解除されます。

DECLARE CURSOR c1 IS SELECT ename FROM emp FOR UPDATE OF sal;BEGIN FOR emp_rec IN c1 LOOP -- FETCH fails on the second iteration INSERT INTO temp VALUES ('still going'); COMMIT; -- releases locks END LOOP;END;

複数のコミットにまたがってフェッチする場合は、ROWID擬似列を使用して CURRENT OF句と同じ処理を実行します。各行の ROWID を選択して、UROWID変数に入れます。その後、更新や削除のときに、ROWID を使用して現在行を識別します。

DECLARE CURSOR c1 IS SELECT ename, job, rowid FROM emp; my_ename emp.ename%TYPE; my_job emp.job%TYPE; my_rowid UROWID;BEGIN OPEN c1; LOOP FETCH c1 INTO my_ename, my_job, my_rowid;

6-44 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 233: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

EXIT WHEN c1%NOTFOUND; UPDATE emp SET sal = sal * 1.05 WHERE rowid = my_rowid; -- this mimics WHERE CURRENT OF c1 COMMIT; END LOOP; CLOSE c1;END;

フェッチされた行は、FOR UPDATE句によってロックされていないため、他のユーザーによって意識せずに変更内容が上書きされる可能性があります。読取り一貫性のために必要な追加領域は、カーソルがクローズされるまで解放されません。そのため、大規模な更新では処理速度が低下する場合があります。

ROWID疑似列を参照するカーソルで %ROWTYPE属性を使用する例を次に示します。

DECLARE CURSOR c1 IS SELECT ename, sal, rowid FROM emp; emp_rec c1%ROWTYPE;BEGIN OPEN c1; LOOP FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; IF ... THEN DELETE FROM emp WHERE rowid = emp_rec.rowid; END IF; END LOOP; CLOSE c1;END;

自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行自律型トランザクションによる独立した作業単位の実行自律型トランザクション自律型トランザクション自律型トランザクション自律型トランザクションは、別の、メイン・トランザクションメイン・トランザクションメイン・トランザクションメイン・トランザクションによって開始される独立したトランザクションです。自律型トランザクションは、メイン・トランザクションをコミットまたはロールバックせずに、SQL 操作を実行してコミットまたはロールバックします。たとえば、監査データをログ表に書き込む場合、監査操作が後で失敗しても、監査データをコミットする必要がある場合があります。すなわち、監査データの記録で問題が発生しても、メイン操作がロールバックされないようにする必要があります。

PL/SQL での SQL 操作の実行 6-45

Page 234: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

図 6-1 に、メイン・トランザクション(MT)から自律型トランザクション(AT)へ制御がどのように流れ、また戻るかを示します。

図図図図 6-1 トランザクション制御の流れトランザクション制御の流れトランザクション制御の流れトランザクション制御の流れ

自律型トランザクションのメリット自律型トランザクションのメリット自律型トランザクションのメリット自律型トランザクションのメリット自律型トランザクションは、開始すると完全に独立します。ロック、リソースまたはコミット依存関係をメイン・トランザクションと共有することはありません。メイン・トランザクションがロールバックする場合でも、イベントや増分再試行カウンタなどのログを取ることができます。

さらに重要な点は、自律型トランザクションは再利用可能なソフトウェア・コンポーネントであるモジュール構造の作成に役立つということです。自律型トランザクションは、ストアド・プロシージャ内部でカプセル化できます。コール側のアプリケーションは、そのストアド・プロシージャによって実行された操作が成功したか失敗したかを知る必要はありません。

自律型トランザクションの定義自律型トランザクションの定義自律型トランザクションの定義自律型トランザクションの定義自律型トランザクションを定義するには、AUTONOMOUS_TRANSACTIONプラグマ(コンパイラ・ディレクティブ)を使用します。プラグマはルーチンを自律型(独立型)としてマークするように PL/SQL コンパイラに指示します。このコンテキストでは、ルーチンには次のものが含まれます。

� トップレベル(ネストしていない)の無名 PL/SQL ブロック

� ローカル、スタンドアロンおよびパッケージのファンクションとプロシージャ

� SQL オブジェクト型のメソッド

� データベース・トリガー

6-46 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 235: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

プラグマは、ルーチンの宣言部の任意の場所でコーディングできます。ただし、見やすくするために、セクションの先頭にプラグマをコーディングしてください。次に構文を示します。

PRAGMA AUTONOMOUS_TRANSACTION;

次の例では、パッケージ・ファンクションを自律型としてマークします。

CREATE PACKAGE banking AS ... FUNCTION balance (acct_id INTEGER) RETURN REAL;END banking;

CREATE PACKAGE BODY banking AS ... FUNCTION balance (acct_id INTEGER) RETURN REAL IS PRAGMA AUTONOMOUS_TRANSACTION; my_bal REAL; BEGIN ... END;END banking;

制限制限制限制限 : パッケージのすべてのサブプログラム(またはオブジェクト型のすべてのメソッド)を自律型としてマークするためにプラグマを使用することはできません。自律型としてマークできるのは、個々のルーチンのみです。

次の例では、スタンドアロン・プロシージャを自律型としてマークします。

CREATE PROCEDURE close_account (acct_id INTEGER, OUT balance) AS PRAGMA AUTONOMOUS_TRANSACTION; my_bal REAL;BEGIN ... END;

次の例では、PL/SQL ブロックを自律型としてマークします。

DECLARE PRAGMA AUTONOMOUS_TRANSACTION; my_empno NUMBER(4);BEGIN ... END;

制限制限制限制限 : ネストした PL/SQL ブロックは自律型としてマークできません。

次の例では、データベース・トリガーを自律型としてマークします。通常のトリガーとは異なり、自律型トリガーには、COMMITや ROLLBACKなどのトランザクション制御文を含めることができます。

PL/SQL での SQL 操作の実行 6-47

Page 236: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

CREATE TRIGGER parts_triggerBEFORE INSERT ON parts FOR EACH ROWDECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN INSERT INTO parts_log VALUES(:new.pnum, :new.pname); COMMIT; -- allowed only in autonomous triggersEND;

自律型トランザクションとネストしたトランザクションの比較自律型トランザクションとネストしたトランザクションの比較自律型トランザクションとネストしたトランザクションの比較自律型トランザクションとネストしたトランザクションの比較自律型トランザクションは別のトランザクションによって開始されますが、これはネストしたトランザクションではありません。その理由は次のとおりです。

� ロックなどのトランザクション・リソースをメイン・トランザクションと共有しません。

� メイン・トランザクションに依存しません。たとえば、メイン・トランザクションがロールバックする場合は、ネストしたトランザクションがロールバックするのに対し、自律型トランザクションはロールバックしません。

� コミットされた変更を、他のトランザクションからすぐに参照できます。(ネストしたトランザクションのコミットされた変更は、メイン・トランザクションがコミットするまで他のトランザクションからは参照できません。)

� 自律型トランザクションで例外が呼び出されると、文レベルのロールバックではなくトランザクション・レベルのロールバックが発生します。

トランザクション・コンテキストトランザクション・コンテキストトランザクション・コンテキストトランザクション・コンテキストメイン・トランザクションはそのコンテキストをネストしたルーチンと共有しますが、自律型トランザクションとは共有しません。ある自律型ルーチンが別の自律型ルーチンを(または自身を再帰的に)コールする場合、ルーチンはトランザクション・コンテキストを共有しません。ある自律型ルーチンが自律型ではないルーチンをコールする場合、ルーチンは同じトランザクション・コンテキストを共有します。

トランザクションの可視性トランザクションの可視性トランザクションの可視性トランザクションの可視性自律型トランザクションによって行われた変更は、自律型トランザクションがコミットすると、他のトランザクションから参照できるようになります。分離レベルが READ COMMITTED

(デフォルト)に設定されている場合、メイン・トランザクションが再開すると、これらの変更をメイン・トランザクションから参照できるようになります。

メイン・トランザクションの分離レベルを SERIALIZABLEに設定すると、その自律型トランザクションによって行われた変更は、再開してもメイン・トランザクションからは参照できません。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

6-48 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 237: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

自律型トランザクションの制御自律型トランザクションの制御自律型トランザクションの制御自律型トランザクションの制御自律型ルーチンの 初の SQL 文でトランザクションが開始されます。1 つのトランザクションが終了すると、次の SQL 文で別のトランザクションが開始されます。カレント・トランザクションは、 後のコミットまたはロールバックよりも後に実行されたすべての SQL 文で構成されます。自律型トランザクションを制御するには、次の文を使用します。これは現在の(アクティブな)トランザクションのみに適用されます。

� COMMIT

� ROLLBACK [TO savepoint_name]

� SAVEPOINT savepoint_name

� SET TRANSACTION

注意注意注意注意 : メイン・トランザクションで設定されたトランザクションのプロパティは、そのトランザクションのみに適用され、自律型トランザクションには適用されません。逆の場合も同じです。

開始と終了開始と終了開始と終了開始と終了

自律型ルーチンの実行部に入ると、メイン・トランザクションは停止します。ルーチンを終了すると、メイン・トランザクションは再開します。

正常に終了するには、すべての自律型トランザクションを明示的にコミットまたはロールバックする必要があります。ルーチン(またはそれによってコールされたルーチン)に保留中のトランザクションがある場合は、例外が呼び出され、保留中のトランザクションはロールバックされます。

コミットとロールバックコミットとロールバックコミットとロールバックコミットとロールバック

COMMITと ROLLBACKはアクティブな自律型トランザクションを終了しますが、自律型ルーチンから抜けるわけではありません。1 つのトランザクションが終了すると、次の SQL 文で別のトランザクションが開始されます。1 つの自律型ルーチンは、複数の COMMIT文を発行する場合、複数の自律型トランザクションを含むことができます。

セーブポイントの使用セーブポイントの使用セーブポイントの使用セーブポイントの使用

セーブポイントの有効範囲は、それが定義されたトランザクションです。メイン・トランザクション内で定義されたセーブポイントは、その自律型トランザクション内で定義されたセーブポイントとは無関係です。実際、メイン・トランザクションと自律型トランザクションのセーブポイントには、同じ名前を使用できます。

ロールバックできるのは、カレント・トランザクション内でマークされたセーブポイントまでです。自律型トランザクション内では、メイン・トランザクション内でマークされたセーブポイントまではロールバックできません。メイン・トランザクションのセーブポイントまでロールバックするには、自律型ルーチンを抜けてメイン・トランザクションを再開する必要があります。

PL/SQL での SQL 操作の実行 6-49

Page 238: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

メイン・トランザクション内では、自律型トランザクションを開始する前にマークされたセーブポイントまでロールバックしても、自律型トランザクションはロールバックされません。自律型トランザクションは、メイン・トランザクションからは完全に独立していることに注意してください。

自律型トランザクションでのエラーの回避自律型トランザクションでのエラーの回避自律型トランザクションでのエラーの回避自律型トランザクションでのエラーの回避

一般的なエラーを回避するには、次の事項を考慮してください。

� メイン・トランザクションが保持するリソースに、自律型トランザクションがアクセスしようとすると、デッドロックが発生します。この場合、Oracle は自律型トランザクションで例外を呼び出します。例外が未処理になった場合、自律型トランザクションはロールバックされます。

� Oracle 初期化パラメータ TRANSACTIONSは、同時トランザクションの 大数を指定します。自律型トランザクションはメイン・トランザクションと同時に実行されるため、この 大数を超える場合があります。

� コミットまたはロールバックせずにアクティブな自律型トランザクションを終了しようとすると、Oracle は例外を呼び出します。例外が未処理になった場合、トランザクションはロールバックされます。

自律型トリガーの使用自律型トリガーの使用自律型トリガーの使用自律型トリガーの使用データベース・トリガーを使用してイベントのログを透過的に取ることができます。ある表に対するすべての挿入を、ロールバックするものも含めて追跡するとします。次の例では、トリガーを使用して、重複する行をシャドウ表に挿入します。トリガーは自律型であるため、メインの表への変更をコミットするかどうかに関係なく、シャドウ表への変更をコミットできます。

-- create a main table and its shadow tableCREATE TABLE parts (pnum NUMBER(4), pname VARCHAR2(15));CREATE TABLE parts_log (pnum NUMBER(4), pname VARCHAR2(15));

-- create an autonomous trigger that inserts into the-- shadow table before each insert into the main tableCREATE TRIGGER parts_trigBEFORE INSERT ON parts FOR EACH ROWDECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN INSERT INTO parts_log VALUES(:new.pnum, :new.pname); COMMIT;END;

-- insert a row into the main table, and then commit the insertINSERT INTO parts VALUES (1040, 'Head Gasket');COMMIT;

6-50 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 239: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

-- insert another row, but then roll back the insertINSERT INTO parts VALUES (2075, 'Oil Pan');ROLLBACK;

-- show that only committed inserts add rows to the main tableSELECT * FROM parts ORDER BY pnum; PNUM PNAME------- --------------- 1040 Head Gasket

-- show that both committed and rolled-back inserts add rows-- to the shadow tableSELECT * FROM parts_log ORDER BY pnum; PNUM PNAME------- --------------- 1040 Head Gasket 2075 Oil Pan

通常のトリガーとは異なり、自律型トリガーはシステム固有の動的 SQL を使用して、DDL文を実行できます(第 7 章「システム固有の動的 SQL を使用した SQL 操作の実行」を参照)。次の例では、表 bonusが更新された後にトリガー bonus_trigが一時データベース表を削除します。

CREATE TRIGGER bonus_trigAFTER UPDATE ON bonusDECLARE PRAGMA AUTONOMOUS_TRANSACTION; -- enables trigger to perform DDLBEGIN EXECUTE IMMEDIATE 'DROP TABLE temp_bonus';END;

データベース・トリガーの詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

SQL からの自律型ファンクションのコールからの自律型ファンクションのコールからの自律型ファンクションのコールからの自律型ファンクションのコールSQL 文からコールされるファンクションは、副作用を制御するための特定の規則に従う必要があります。(8-29 ページの「PL/SQL サブプログラムの副作用の制御」を参照。)この規則に違反していないかどうかを確認するには、RESTRICT_REFERENCESプラグマを使用できます。プラグマは、ファンクションがデータベース表またはパッケージ変数に対する読込みまたは書込みを行っていないことを示します。(詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照。)

PL/SQL での SQL 操作の実行 6-51

Page 240: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

自律型トランザクションによる独立した作業単位の実行

ただし、自律型ルーチンの動作に関係なく、「データベースに読込み禁止状態」(RNDS)および「データベースへの書込み禁止状態」(WNDS)の規則に違反しないように定義できます。次の例に示すように、これは便利な機能です。問合せからパッケージ・ファンクションlog_msgをコールすると、「データベースへの書込み禁止状態」の規則に違反することなく、データベース表 debug_outputにメッセージが挿入されます。

-- create the debug tableCREATE TABLE debug_output (msg VARCHAR2(200));

-- create the package specCREATE PACKAGE debugging AS FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2; PRAGMA RESTRICT_REFERENCES(log_msg, WNDS, RNDS);END debugging;

-- create the package bodyCREATE PACKAGE BODYq debugging AS FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN -- the following insert does not violate the constraint -- WNDS because this is an autonomous routine INSERT INTO debug_output VALUES (msg); COMMIT; RETURN msg; END;END debugging;

-- call the packaged function from a queryDECLARE my_empno NUMBER(4); my_ename VARCHAR2(15);BEGIN ... SELECT debugging.log_msg(ename) INTO my_ename FROM emp WHERE empno = my_empno; -- even if you roll back in this scope, the insert -- into 'debug_output' remains committed because -- it is part of an autonomous transaction IF ... THEN ROLLBACK; END IF;END;

6-52 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 241: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の動的 SQL を使用

7

システム固有の動的システム固有の動的システム固有の動的システム固有の動的 SQL を使用したを使用したを使用したを使用した

SQL 操作の実行操作の実行操作の実行操作の実行

この章では、システム固有の動的 SQL(略して動的 SQL)を使用する方法について説明します。これは、SQL 文を実行時に記述および処理することで、プログラムをより柔軟に使用できるようにする PL/SQL インタフェースです。

動的 SQL では、任意の種類の SQL 文(データ定義文およびデータ制御文を含む)を直接実行できます。表名、WHERE句およびその他の情報が事前に不明でも、文を記述できます。

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

� 動的 SQL(7-2 ページ)

� 動的 SQL が必要になる場合(7-2 ページ)

� EXECUTE IMMEDIATE 文の使用(7-3 ページ)

� 動的 SQL を使用した動的問合せの構築(7-5 ページ)

� バルク動的 SQL の使用(7-8 ページ)

� 動的 SQL のガイドライン(7-10 ページ)

した SQL 操作の実行 7-1

Page 242: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL

動的動的動的動的 SQL一部のプログラムは、一部の情報が事前に不明な状態で SQL 文を記述および処理する必要があります。たとえば、レポート・アプリケーションでは、生成する様々なレポートに合わせて異なる SELECT文を記述し、新しい表および列名に置き換えたり、様々な列で順序付けまたはグループ化を行う必要がある場合があります。また、データベース管理アプリケーションでは、CREATE、DROP、GRANTなどの、PL/SQL プログラム内に直接コーディングできない文を発行する場合があります。このような文は動的 SQL 文と呼ばれます。

動的 SQL 文は、文字列として実行時に記述されます。文字列は、SQL 文または PL/SQL ブロックのテキストを含みます。また、バインド引数のプレースホルダも含むことができます。プレースホルダ名には、接頭辞としてコロンが付きます。名前自体は関係ありません。たとえば、PL/SQL は次の文字列を区別しません。

'DELETE FROM emp WHERE sal > :my_sal AND comm < :my_comm''DELETE FROM emp WHERE sal > :s AND comm < :c'

動的 SQL 文を処理するには、ほとんどの場合 EXECUTE IMMEDIATE文を使用します。複数行の問合せ(SELECT文)を処理する場合は、OPEN-FOR文、FETCH文および CLOSE文を使用します。

動的動的動的動的 SQL が必要になる場合が必要になる場合が必要になる場合が必要になる場合動的 SQL は、次のような場合に必要になります。

� SQL データ定義文(CREATEなど)、データ制御文(GRANTなど)またはセッション制御文(ALTER SESSIONなど)を実行する場合。INSERT文、UPDATE文および DELETE文とは異なり、これらの文は PL/SQL プログラム内に直接含めることができません。

� 柔軟性が必要な場合。たとえば、スキーマ・オブジェクトの名前をパラメータとしてプロシージャに渡す場合があります。また、SELECT文の WHERE句に対して異なる検索条件を記述する場合があります。

� 列の数、名前またはデータ型が事前に不明な状態で問合せを発行する場合。この場合、OPEN-FOR文ではなく DBMS_SQLパッケージを使用します。

古いコードで DBMS_SQLパッケージを使用している場合、この章で説明されているとおりEXECUTE IMMEDIATEおよび OPEN-FORを使用すると、通常パフォーマンスが向上し、コードが読みやすくなり、オブジェクトおよびコレクションのサポートなどの追加機能が提供されます。(DBMS_SQL との比較は、『Oracle Database アプリケーション開発者ガイド -基礎編』を参照してください。)

7-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 243: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文の使用

EXECUTE IMMEDIATE 文の使用文の使用文の使用文の使用EXECUTE IMMEDIATE文は、動的 SQL 文または無名 PL/SQL ブロックを準備(解析)し、即時に実行します。

EXECUTE IMMEDIATEの主な引数は、実行する SQL 文を含む文字列です。連結を使用して文字列を記述するか、または事前定義の文字列を使用できます。

複数行の問合せの場合を除いて、動的文字列には任意の SQL 文( 後のセミコロンなし)または任意の PL/SQL ブロック( 後のセミコロン付き)を含めることができます。また、バインド引数のプレースホルダ(接頭辞にコロンが付いた任意の名前)を含めることもできます。この場合、INTO句、USING句および RETURNING INTO句を使用して、プレースホルダに対応する PL/SQL 変数を指定します。

プレースホルダは、WHERE句の条件テストなど、SQL 文の中で変数を置き換えることができる場所にのみ使用できます。スキーマ・オブジェクトの名前としてプレースホルダを使用することはできません。正しい方法は、7-11 ページの「パラメータとしてのスキーマ・オブジェクト名の引渡し」を参照してください。

INTO句は単一行の問合せの場合に使用され、検索された列の値を入れる変数またはレコードを指定します。問合せによって取り出された値それぞれに対して、INTO句の中に、対応する型互換性変数が存在している必要があります。

RETURNING INTO句は、RETURNING句のある(BULK COLLECT句のない)DML 文の場合にのみ使用され、列の値が戻される変数を指定します。DML 文によって戻された値それぞれに対して、RETURNING INTO句の中に、対応する型互換性変数が存在している必要があります。

バインド引数は、すべて USING句に入れることができます。デフォルトのパラメータ・モードは INです。RETURNING句を持つ DML 文の場合は、パラメータ・モードを指定しなくても、OUT引数を RETURNING INTO句に入れることができます。USING句とRETURNING INTO句の両方を使用する場合、USING句には IN引数のみを含めることができます。

実行時に、バインド引数は動的文字列内の対応するプレースホルダを置き換えます。すべてのプレースホルダを USING句内または RETURNING INTO句内(あるいはその両方)のバインド引数に関連付ける必要があります。数値リテラル、文字リテラルおよび文字列リテラルはバインド引数として使用できますが、ブール・リテラル(TRUE、FALSEおよび NULL)は使用できません。動的文字列に NULL を渡すには、回避策を使用する必要があります。7-13ページの「動的 SQL への NULL の引渡し」を参照してください。

動的 SQL はすべての SQL データ型をサポートしています。たとえば、定義変数やバインド引数をコレクション、LOB、オブジェクト型のインスタンスおよび ref とすることができます。

通常、動的 SQL は PL/SQL 固有の型をサポートしていません。たとえば、定義変数やバインド引数をブールまたは結合配列にすることはできません。例外として、PL/SQL レコードを INTO句に入れることができます。

システム固有の動的 SQL を使用した SQL 操作の実行 7-3

Page 244: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文の使用

動的 SQL 文は、バインド引数の新しい値を使用して繰り返し実行できます。ただし、EXECUTE IMMEDIATEは実行のたびに動的文字列を準備するため、オーバーヘッドが発生します。

例例例例 7-1 動的動的動的動的 SQL の例の例の例の例

次の PL/SQL ブロックには動的 SQL の例がいくつか含まれています。

DECLARE sql_stmt VARCHAR2(200); plsql_block VARCHAR2(500); emp_id NUMBER(4) := 7566; salary NUMBER(7,2); dept_id NUMBER(2) := 50; dept_name VARCHAR2(14) := 'PERSONNEL'; location VARCHAR2(13) := 'DALLAS'; emp_rec emp%ROWTYPE;BEGIN EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)'; sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)'; EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location; sql_stmt := 'SELECT * FROM emp WHERE empno = :id'; EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id; plsql_block := 'BEGIN emp_pkg.raise_salary(:id, :amt); END;'; EXECUTE IMMEDIATE plsql_block USING 7788, 500; sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1 RETURNING sal INTO :2'; EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary; EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num' USING dept_id; EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';END;/

例例例例 7-2 表名および表名および表名および表名および WHERE 句を受け入れる動的句を受け入れる動的句を受け入れる動的句を受け入れる動的 SQL プロシージャプロシージャプロシージャプロシージャ

次の例では、スタンドアロン・プロシージャはデータベース表の名前とオプションの WHERE句条件を受け入れます。条件を省略すると、プロシージャは表の中のすべての行を削除します。条件が省略されていなければ、プロシージャは条件を満たす行のみを削除します。

CREATE OR REPLACE PROCEDURE delete_rows ( table_name IN VARCHAR2, condition IN VARCHAR2 DEFAULT NULL) AS where_clause VARCHAR2(100) := ' WHERE ' || condition;BEGIN IF condition IS NULL THEN where_clause := NULL; END IF; EXECUTE IMMEDIATE 'DELETE FROM ' || table_name || where_clause;END;/

7-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 245: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL を使用した動的問合せの構築

動的動的動的動的 SQL 文字列におけるバインド変数のパラメータ・モードの指定文字列におけるバインド変数のパラメータ・モードの指定文字列におけるバインド変数のパラメータ・モードの指定文字列におけるバインド変数のパラメータ・モードの指定USING句を使用すると、モードはデフォルトで INに設定されるため、入力バインド引数のパラメータ・モードを指定する必要はありません。

RETURNING INTO句を使用すると、パラメータ・モードは OUTになるため、出力バインド引数のパラメータ・モードを指定できません。

次のようにより複雑な場合は、パラメータ・モードを指定する必要があります。ここでは、動的 PL/SQL ブロックからプロシージャをコールしています。

CREATE PROCEDURE create_dept ( deptno IN OUT NUMBER, dname IN VARCHAR2, loc IN VARCHAR2) ASBEGIN SELECT deptno_seq.NEXTVAL INTO deptno FROM dual; INSERT INTO dept VALUES (deptno, dname, loc);END;/

動的 PL/SQL ブロックからプロシージャをコールするには、次のように、仮パラメータdeptnoに対応付けられたバインド引数に、IN OUTモードを指定する必要があります。

DECLARE plsql_block VARCHAR2(500); new_deptno NUMBER(2); new_dname VARCHAR2(14) := 'ADVERTISING'; new_loc VARCHAR2(13) := 'NEW YORK';BEGIN plsql_block := 'BEGIN create_dept(:a, :b, :c); END;'; EXECUTE IMMEDIATE plsql_block USING IN OUT new_deptno, new_dname, new_loc; IF new_deptno > 90 THEN ...END;/

動的動的動的動的 SQL を使用した動的問合せの構築を使用した動的問合せの構築を使用した動的問合せの構築を使用した動的問合せの構築動的な複数行の問合せを処理するには、OPEN-FOR文、FETCH文および CLOSE文の 3 つの文を使用します。まず、OPEN-FOR文でカーソル変数を複数行問合せ用にオープンします。次に、FETCH文で結果セットから一度に 1 行ずつ行を取り出します。すべての行が処理された後に、CLOSE文でカーソル変数をクローズします。(カーソル変数の詳細は、6-25 ページの「カーソル変数(REF CURSOR)の使用」を参照してください。)

システム固有の動的 SQL を使用した SQL 操作の実行 7-5

Page 246: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード、オブジェクトおよびコレクションの動的 SQL の例

レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的レコード、オブジェクトおよびコレクションの動的 SQL の例の例の例の例

例例例例 7-3 レコードへの動的レコードへの動的レコードへの動的レコードへの動的 SQL フェッチフェッチフェッチフェッチ

次の例に示すように、動的な複数行の問合せの結果セットから行をフェッチしてレコードに入れることができます。

DECLARE TYPE EmpCurTyp IS REF CURSOR; emp_cv EmpCurTyp; emp_rec emp%ROWTYPE; sql_stmt VARCHAR2(200); my_job VARCHAR2(15) := 'CLERK';BEGIN sql_stmt := 'SELECT * FROM emp WHERE job = :j'; OPEN emp_cv FOR sql_stmt USING my_job; LOOP FETCH emp_cv INTO emp_rec; EXIT WHEN emp_cv%NOTFOUND; -- process record END LOOP; CLOSE emp_cv;END;/

例例例例 7-4 オブジェクト型とコレクションの動的オブジェクト型とコレクションの動的オブジェクト型とコレクションの動的オブジェクト型とコレクションの動的 SQL

次の例は、オブジェクトとコレクションの使用方法を示しています。たとえば、オブジェクト型 Personおよび VARRAY型 Hobbiesを、次のように定義するとします。

CREATE TYPE Person AS OBJECT (name VARCHAR2(25), age NUMBER);CREATE TYPE Hobbies IS VARRAY(10) OF VARCHAR2(25);

動的 SQL を使用すると、これらの型を使用するパッケージを作成できます。

CREATE OR REPLACE PACKAGE teams AS PROCEDURE create_table (tab_name VARCHAR2); PROCEDURE insert_row (tab_name VARCHAR2, p Person, h Hobbies); PROCEDURE print_table (tab_name VARCHAR2);END;/

CREATE OR REPLACE PACKAGE BODY teams AS PROCEDURE create_table (tab_name VARCHAR2) IS BEGIN EXECUTE IMMEDIATE 'CREATE TABLE ' || tab_name || ' (pers Person, hobbs Hobbies)';

7-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 247: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード、オブジェクトおよびコレクションの動的 SQL の例

END;

PROCEDURE insert_row ( tab_name VARCHAR2, p Person, h Hobbies) IS BEGIN EXECUTE IMMEDIATE 'INSERT INTO ' || tab_name || ' VALUES (:1, :2)' USING p, h; END;

PROCEDURE print_table (tab_name VARCHAR2) IS TYPE RefCurTyp IS REF CURSOR; cv RefCurTyp; p Person; h Hobbies; BEGIN OPEN cv FOR 'SELECT pers, hobbs FROM ' || tab_name; LOOP FETCH cv INTO p, h; EXIT WHEN cv%NOTFOUND; -- print attributes of 'p' and elements of 'h' END LOOP; CLOSE cv; END;END;/

無名 PL/SQL ブロックから、パッケージ teamsのプロシージャをコールできます。

DECLARE team_name VARCHAR2(15);BEGIN team_name := 'Notables'; teams.create_table(team_name); teams.insert_row(team_name, Person('John', 31), Hobbies('skiing', 'coin collecting', 'tennis')); teams.insert_row(team_name, Person('Mary', 28), Hobbies('golf', 'quilting', 'rock climbing')); teams.print_table(team_name);END;/

システム固有の動的 SQL を使用した SQL 操作の実行 7-7

Page 248: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

バルク動的 SQL の使用

バルク動的バルク動的バルク動的バルク動的 SQL の使用の使用の使用の使用バルク SQL では、個々の要素ではなくコレクション全体がやり取りされます。この手法では、PL/SQL エンジンと SQL エンジンの間のコンテキスト切替えの回数を 小限に抑えることによって、パフォーマンスを向上させます。すべての反復で SQL 文を発行するループではなく、1 つの文を使用できます。

次のコマンド、句およびカーソル属性を使用すると、アプリケーションでバルク SQL 文を作成して、実行時に動的に実行できます。

BULK FETCH文BULK EXECUTE IMMEDIATE文FORALL文COLLECT INTO句RETURNING INTO句%BULK_ROWCOUNTカーソル属性

前述の文、句およびカーソル属性の静的バージョンについては、11-9 ページの「DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)」を参照してください。背景情報も記載されています。

動的動的動的動的 SQL とバルクとバルクとバルクとバルク SQL の使用の使用の使用の使用バルク・バインドを使用すると、SQL 文の変数を値のコレクションにバインドできます。コレクション型には、任意の PL/SQL コレクション型(索引付き表、ネストした表またはVARRAY)を使用できます。コレクション要素には、CHAR、DATE、NUMBERなどの SQLデータ型が必要です。バルク動的バインドがサポートされる文は、EXECUTE IMMEDIATE、FETCHおよび FORALLです。

EXECUTE IMMEDIATEEXECUTE IMMEDIATE文に BULK COLLECT INTO句を使用すると、問合せの結果セットの各列の値を個別のコレクションに格納できます。

EXECUTE IMMEDIATE文に RETURNING BULK COLLECT INTO句を使用すると、INSERT文、UPDATE文または DELETE文の結果をコレクション・セットに格納できます。

FETCHFETCH文に BULK COLLECT INTO句を使用すると、カーソルの各列からフェッチした値を個別のコレクションに格納できます。

FORALLFORALL文には、EXECUTE IMMEDIATE文に RETURNING BULK COLLECT INTOを指定して含めることができます。INSERT文、UPDATE文または DELETE文のすべての結果を、コレクション・セットに格納できます。

7-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 249: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

バルク動的 SQL の使用

USING句を使用して、EXECUTE IMMEDIATE文に添字付きのコレクション要素を渡すことができます。添字付きの要素は、EXECUTE IMMEDIATEの文字列引数に直接連結できません。たとえば、表名のコレクションを構築し、それぞれの反復が異なる表に適用されるFORALL文を記述することはできません。

バルク動的バインドの例バルク動的バインドの例バルク動的バインドの例バルク動的バインドの例

例例例例 7-5 BULK COLLECT INTO 句を使用した動的句を使用した動的句を使用した動的句を使用した動的 SQL

動的な問合せでは、BULK COLLECT INTO句を使用して定義変数をバインドできます。次の例のように、この句をバルク FETCH文またはバルク EXECUTE IMMEDIATE文に使用できます。

DECLARE TYPE EmpCurTyp IS REF CURSOR; TYPE NumList IS TABLE OF NUMBER; TYPE NameList IS TABLE OF VARCHAR2(15); emp_cv EmpCurTyp; empnos NumList; enames NameList; sals NumList;BEGIN OPEN emp_cv FOR 'SELECT empno, ename FROM emp'; FETCH emp_cv BULK COLLECT INTO empnos, enames; CLOSE emp_cv;

EXECUTE IMMEDIATE 'SELECT sal FROM emp' BULK COLLECT INTO sals;END;/

例例例例 7-6 RETURNING BULK COLLECT INTO 句を使用した動的句を使用した動的句を使用した動的句を使用した動的 SQL

出力バインド変数を使用できるのは、INSERT、UPDATEおよび DELETE文のみです。EXECUTE IMMEDIATE文に RETURNING BULK COLLECT INTO句を指定して、変数をバルク・バインドします。

DECLARE TYPE NameList IS TABLE OF VARCHAR2(15); enames NameList; bonus_amt NUMBER := 500; sql_stmt VARCHAR(200);BEGIN sql_stmt := 'UPDATE emp SET bonus = :1 RETURNING ename INTO :2'; EXECUTE IMMEDIATE sql_stmt

システム固有の動的 SQL を使用した SQL 操作の実行 7-9

Page 250: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

USING bonus_amt RETURNING BULK COLLECT INTO enames;END;/

例例例例 7-7 FORALL 文中の動的文中の動的文中の動的文中の動的 SQL

SQL 文中で入力変数をバインドするには、次のように FORALL文と USING句を使用できます。SQL 文を問合せにすることはできません。

DECLARE TYPE NumList IS TABLE OF NUMBER; TYPE NameList IS TABLE OF VARCHAR2(15); empnos NumList; enames NameList;BEGIN empnos := NumList(1,2,3,4,5); FORALL i IN 1..5 EXECUTE IMMEDIATE 'UPDATE emp SET sal = sal * 1.1 WHERE empno = :1 RETURNING ename INTO :2' USING empnos(i) RETURNING BULK COLLECT INTO enames; ...END;/

動的動的動的動的 SQL のガイドラインのガイドラインのガイドラインのガイドラインこの項では、動的 SQL を十分に活用する方法、および頻繁に発生する問題を回避する方法について説明します。

動的動的動的動的 SQL でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略単一の SQL 文を 1 つの文字列として記述する場合、文末にセミコロンを置かないでください。

無名 PL/SQL ブロックを記述する場合、各 PL/SQL 文の文末および無名ブロックの 後にセミコロンを置きます。

次に例を示します。

BEGIN EXECUTE IMMEDIATE 'dbms_output.put_line(''No semicolon'')'; EXECUTE IMMEDIATE 'BEGIN dbms_output.put_line(''semicolons''); END;';END;

7-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 251: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

バインド変数を使用した動的バインド変数を使用した動的バインド変数を使用した動的バインド変数を使用した動的 SQL のパフォーマンスの向上のパフォーマンスの向上のパフォーマンスの向上のパフォーマンスの向上PL/SQL に INSERT文、UPDATE文、DELETE文および SELECT文を直接コーディングすると、PL/SQL は、これらの文が SQL で効率的に動作するように、変数を自動的にバインド変数に変換します。このような文を動的 SQL に記述した場合、同等のパフォーマンスを得るには、自分でバインド変数を指定する必要があります。

次の例では、Oracle は emp_idの個別値ごとに異なるカーソルをオープンしています。この場合、各文が解析およびキャッシュされるため、リソースの競合およびパフォーマンスの低下が発生する可能性があります。

CREATE PROCEDURE fire_employee (emp_id NUMBER) ASBEGIN EXECUTE IMMEDIATE 'DELETE FROM emp WHERE empno = ' || TO_CHAR(emp_id);END;/

バインド変数を使用すると、パフォーマンスが向上します。これによって、Oracle はemp_idの異なる値に対して同じカーソルを再利用できるようになります。

CREATE PROCEDURE fire_employee (emp_id NUMBER) ASBEGIN EXECUTE IMMEDIATE 'DELETE FROM emp WHERE empno = :num' USING emp_id;END;/

パラメータとしてのスキーマ・オブジェクト名の引渡しパラメータとしてのスキーマ・オブジェクト名の引渡しパラメータとしてのスキーマ・オブジェクト名の引渡しパラメータとしてのスキーマ・オブジェクト名の引渡し任意のデータベース表の名前を受け入れ、その表をスキーマから削除するプロシージャが必要だとします。この場合、オブジェクト名を含む文で文字列を記述し、EXECUTE IMMEDIATEを使用してその文を実行する必要があります。

CREATE PROCEDURE drop_table (table_name IN VARCHAR2) ASBEGIN EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;END;/

USING句を使用して、表名をバインド変数として渡すのではなく、連結を使用して文字列を記述します。

システム固有の動的 SQL を使用した SQL 操作の実行 7-11

Page 252: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

動的動的動的動的 SQL での重複するプレースホルダの使用での重複するプレースホルダの使用での重複するプレースホルダの使用での重複するプレースホルダの使用動的 SQL 文のプレースホルダは、USING句内のバインド引数に、名前ではなく位置によって対応付けられます。プレースホルダの順序を、:a、:a、:b、:bのように指定した場合、USING句に 4 つの項目を含める必要があります。たとえば、次のような動的文字列があるとします。

sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y, :x)';

x という名前が繰り返されていることは重要ではありません。4 つの異なるバインド変数を使用して、対応する USING句をコーディングできます。

EXECUTE IMMEDIATE sql_stmt USING a, a, b, a;

動的 SQL 文が PL/SQL ブロックを表している場合、重複するプレースホルダには異なる規則が適用されます。一意の各プレースホルダは、USING句の 1 つの項目にマップされます。同じプレースホルダが 2 回以上指定されている場合、その名前に対するすべての参照がUSING句内の 1 つのバインド引数に対応します。次の例では、プレースホルダ Xに対するすべての参照が 初のバインド変数 Aに関連付けられ、2 番目の一意のプレースホルダ Yが2 番目のバインド変数 B に関連付けられています。

DECLARE a NUMBER := 4; b NUMBER := 7;BEGIN plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END;' EXECUTE IMMEDIATE plsql_block USING a, b;END;/

動的動的動的動的 SQL でのカーソル属性の使用でのカーソル属性の使用でのカーソル属性の使用でのカーソル属性の使用SQL のカーソル属性 %FOUND、%ISOPEN、%NOTFOUNDおよび %ROWCOUNTは、動的 SQL の中で INSERT文、UPDATE文、DELETE文または 1 行の SELECT文を発行した場合に機能します。

EXECUTE IMMEDIATE 'DELETE FROM employees WHERE employee_id > 1000';rows_deleted := SQL%ROWCOUNT;

同様に、カーソル変数名にカーソル属性を追加すると、複数行の問合せの実行に関する情報が戻されます。

OPEN c1 FOR 'SELECT * FROM employees';FETCH c1 BULK COLLECT INTO rec_tab;rows_fetched := c1%ROWCOUNT;

カーソル属性の詳細は、6-35 ページの「カーソル式の使用」を参照してください。

7-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 253: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

動的動的動的動的 SQL へのへのへのへの NULL の引渡しの引渡しの引渡しの引渡しリテラル NULLは、USING句の中では使用できません。この制限を回避するには、キーワード NULLを未初期化の変数で置き換えます。

DECLARE a_null CHAR(1); -- set to NULL automatically at run timeBEGIN EXECUTE IMMEDIATE 'UPDATE emp SET comm = :x' USING a_null;END;/

動的動的動的動的 SQL でのデータベース・リンクの使用でのデータベース・リンクの使用でのデータベース・リンクの使用でのデータベース・リンクの使用PL/SQL サブプログラムは、データベース・リンクを使用してリモート・データベースにあるオブジェクトを参照する動的 SQL 文を実行できます。

PROCEDURE delete_dept (db_link VARCHAR2, dept_id INTEGER) ISBEGIN EXECUTE IMMEDIATE 'DELETE FROM departments@' || db_link || ' WHERE deptno = :num' USING dept_id;END;/

リモート・プロシージャ・コール(RPC)のターゲットは、動的 SQL 文を含むことができます。たとえば、表内の行の数を戻す次のスタンドアロン・ファンクションが、シカゴのデータベースに常駐するとします。

CREATE FUNCTION row_count (tab_name VARCHAR2) RETURN INTEGER AS rows INTEGER;BEGIN EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || tab_name INTO rows; RETURN rows;END;/

無名ブロックから、次のようにしてファンクションをリモートでコールできます。

DECLARE emp_count INTEGER;BEGIN emp_count := row_count@chicago('employees');END;/

システム固有の動的 SQL を使用した SQL 操作の実行 7-13

Page 254: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

動的動的動的動的 SQL での実行者権限の使用での実行者権限の使用での実行者権限の使用での実行者権限の使用動的 SQL を使用すると、スキーマ管理プロシージャを記述できます。このプロシージャは、1 つのスキーマ内に集中させ、他のスキーマからコールしたり、他のスキーマ内のオブジェクトに対して操作を実行することができます。

たとえば、このプロシージャを使用して、すべての種類のデータベース・オブジェクトを削除できます。

CREATE OR REPLACE PROCEDURE drop_it (kind IN VARCHAR2, name INVARCHAR2)AUTHID CURRENT_USERASBEGIN EXECUTE IMMEDIATE 'DROP ' || kind || ' ' || name;END;/

このプロシージャが、HRスキーマの一部であると想定します。AUTHID句を指定しない場合、プロシージャは、どのスキーマからコールされたかにかかわらず常に HRスキーマ内のオブジェクトを削除します。オブジェクトの完全修飾名を渡した場合でも、このプロシージャは他のスキーマを変更する権限を持ちません。

AUTHID句を使用することで、これらの制限を回避できます。これによって、プロシージャは起動したユーザーの権限で実行され、未修飾の参照はそのスキーマ内のオブジェクトを参照します。

詳細は、8-20 ページの「実行者権限と定義者権限の使用(AUTHID 句)」を参照してください。

動的動的動的動的 SQL でのでのでのでの RESTRICT_REFERENCES プラグマの使用プラグマの使用プラグマの使用プラグマの使用SQL 文からコールされるファンクションは、副作用を制御するための特定の規則に従う必要があります。(8-29 ページの「PL/SQL サブプログラムの副作用の制御」を参照。)この規則に違反していないかどうかを確認するには、RESTRICT_REFERENCESプラグマを使用できます。プラグマは、ファンクションがデータベース表またはパッケージ変数に対する読込みまたは書込みを行っていないことを示します(詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照)。

ファンクション本体に動的 INSERT文、UPDATE文または DELETE文が含まれている場合、そのファンクションは常に「データベースへの書込み禁止状態」(WNDS)および「データベースに読込み禁止状態」(RNDS)の規則に違反します。PL/SQL では、これらの副作用を自動的に検出できません。これは、動的 SQL 文がコンパイル時ではなく実行時にチェックされるためです。EXECUTE IMMEDIATE文内では、INTO句のみがコンパイル時に RNDSの規則に違反していないかどうかがチェックされます。

7-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 255: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

動的動的動的動的 SQL でのデッドロックの回避でのデッドロックの回避でのデッドロックの回避でのデッドロックの回避まれに、SQL データ定義文の実行によってデッドロックが発生することがあります。たとえば、次のプロシージャは自身を削除しようとしているため、デッドロックが発生します。デッドロックを回避するには、サブプログラムまたはパッケージを、使用中に ALTERで変更したり、DROPで削除しないでください。

CREATE OR REPLACE PROCEDURE calc_bonus (emp_id NUMBER) ASBEGIN EXECUTE IMMEDIATE 'DROP PROCEDURE calc_bonus'; -- deadlock!END;/

USING 句の下位互換性句の下位互換性句の下位互換性句の下位互換性動的 INSERT文、UPDATE文または DELETE文に RETURNING句がある場合、出力バインド引数を RETURNING INTO句または USING句に入れることができます。新しいアプリケーションでは、RETURNING INTO句を使用します。古いアプリケーションでは、USING句を引き続き使用できます。

システム固有の動的 SQL を使用した SQL 操作の実行 7-15

Page 256: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

動的 SQL のガイドライン

7-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 257: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

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

8

PL/SQL のサブプログラムの使用のサブプログラムの使用のサブプログラムの使用のサブプログラムの使用

この章では、文の集合を、再利用可能なサブプログラムとして作成する方法について説明します。サブプログラムは、メンテナンスしやすいモジュール構造のアプリケーションを構成するビルディング・ブロックと似ています。

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

� サブプログラム(8-2 ページ)

� PL/SQL サブプログラムのメリット(8-3 ページ)

� PL/SQL プロシージャ(8-3 ページ)

� PL/SQL ファンクション(8-4 ページ)

� ネストした PL/SQL サブプログラムの宣言(8-7 ページ)

� PL/SQL サブプログラムへのパラメータの引渡し(8-7 ページ)

� サブプログラム名のオーバーロード(8-12 ページ)

� サブプログラムのコールの解決方法(8-15 ページ)

� 実行者権限と定義者権限の使用(AUTHID 句)(8-20 ページ)

� PL/SQL での再帰の使用(8-27 ページ)

� 外部サブプログラムのコール(8-27 ページ)

� PL/SQL Server Pages(PSP)を使用した動的 Web ページの作成(8-29 ページ)

使用 8-1

Page 258: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラム

サブプログラムサブプログラムサブプログラムサブプログラムサブプログラムは、パラメータの組を指定してコールできる、名前の付けられた PL/SQL ブロックです。PL/SQL にはプロシージャとファンクションの 2 種類のサブプログラムがあります。一般に、プロシージャはアクションを実行するために使用し、ファンクションは値を計算するために使用します。

無名ブロックと同様に、サブプログラムは次の部分から構成されます。

� 宣言部 : 型、カーソル、定数、変数、例外およびネストされたサブプログラムを宣言します。これらの項目はローカルで、サブプログラムを終了すると消去されます。

� 実行部 : 値の代入、実行の制御および Oracle データの操作を実行する文があります。

� オプションの例外処理部 : ランタイム・エラー状態を処理します。

例例例例 8-1 単純な単純な単純な単純な PL/SQL プロシージャプロシージャプロシージャプロシージャ

入力パラメータと出力パラメータの両方を受け取り、潜在的なエラーを処理する文字列操作プロシージャの例を次に示します。

CREATE OR REPLACE PROCEDURE double( original IN VARCHAR2, new_string OUT VARCHAR2)ASBEGIN new_string := original || original; EXCEPTION WHEN VALUE_ERROR THEN dbms_output.put_line('Output buffer not long enough.');END;/

例例例例 8-2 単純な単純な単純な単純な PL/SQL ファンクションファンクションファンクションファンクション

一時的な結果を保持するローカル変数を宣言し、終了時に値を戻す数値ファンクションの例を次に示します。

CREATE OR REPLACE FUNCTION square(original NUMBER)RETURN NUMBERAS original_squared NUMBER;BEGIN original_squared := original * original; RETURN original_squared;END;/

8-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 259: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL プロシージャ

PL/SQL サブプログラムのメリットサブプログラムのメリットサブプログラムのメリットサブプログラムのメリットサブプログラムを使用すると、PL/SQL 言語を拡張できます。プロシージャは新しい文のように機能します。ファンクションは新しい式および演算子のように機能します。

サブプログラムを使用すると、プログラムを管理の容易な、正しく定義されたモジュールに分けることができます。この特性を利用すると、トップダウン設計と段階的詳細化アプローチによって問題を解決できます。

サブプログラムによって、再利用性が向上します。テスト済のサブプログラムは、いくつものアプリケーションで再利用できます。PL/SQL サブプログラムは、多くの異なる環境からコールできます。そのため、新しい言語または API を使用してデータベースにアクセスするたびにサブプログラムを 初から作成しなおす必要はありません。

サブプログラムによって、メンテナンス性が向上します。コール元のサブプログラムを変更することなく、サブプログラムの内部を変更できます。パッケージやオブジェクト型などの、メンテナンス性を向上する他の機能においても、サブプログラムは重要な役割を果たします。

ダミーのサブプログラム(スタブ)を使用すると、メイン・プログラムのテストが終了するまで、プロシージャまたはファンクションを定義しないで済ますことができます。処理の詳細にとらわれることなく、抽象的な思考方法によるトップダウン手法でアプリケーションを設計できます。

PL/SQL サブプログラムを使用して API を定義する場合は、サブプログラムを PL/SQLパッケージにグループ化することで、コードをさらに再利用しやすく、メンテナンス性の高いものにできます。パッケージの詳細は、第 9 章「PL/SQL パッケージの使用」を参照してください。

PL/SQL プロシージャプロシージャプロシージャプロシージャプロシージャとは、特定のアクションを実行するサブプログラムのことです。プロシージャを作成するには、SQL CREATE PROCEDURE文を使用します。プロシージャの名前、パラメータ、ローカル変数および BEGIN-ENDブロック(コードを含み、例外を処理する)を指定します。

各パラメータでは、次の内容を指定します。

� 名前。

� パラメータ・モード(IN、OUTまたは IN OUT)。パラメータ・モードを省略した場合、デフォルトは INです。オプションの NOCOPYキーワードを指定すると、サイズの大きい OUTパラメータまたは IN OUTパラメータの処理がスピードアップします。

� データ型。型のみを指定し、長さや精度の制約は指定しません。

� デフォルト値(オプション)。

PL/SQL のサブプログラムの使用 8-3

Page 260: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ファンクション

プロシージャの実行時に、プロシージャを定義したユーザーのスキーマおよび権限を使用するか、プロシージャをコールするユーザーのスキーマおよび権限を使用するかを指定できます。詳細は、8-20 ページの「実行者権限と定義者権限の使用(AUTHID 句)」を参照してください。

プロシージャをカレント・トランザクションの一部として実行するか、コール元のトランザクションを終了することなくプロシージャ自身のトランザクションで COMMITまたはROLLBACKを実行するかを指定できます。詳細は、6-45 ページの「自律型トランザクションによる独立した作業単位の実行」を参照してください。

このようにして作成されたプロシージャは、データベースに格納されます。CREATE PROCEDURE文は、SQL*Plus またはシステム固有の動的 SQL を使用したプログラムから対話式で実行できます(第 7 章「システム固有の動的 SQL を使用した SQL 操作の実行」を参照)。

プロシージャには、仕様部と本体の 2 つの部分があります。プロシージャの仕様部は、キーワード PROCEDUREで始め、プロシージャ名またはパラメータ・リストで終わります。パラメータ宣言はオプションです。パラメータを取らないプロシージャではカッコを書きません。

プロシージャの本体は、キーワード IS(または AS)で始め、キーワード ENDで終わります。END の後には、オプションとしてプロシージャ名を続けることができます。プロシージャの本体には、宣言部、実行部、例外処理部(オプション)の 3 つの部分があります。

宣言部では、ローカル宣言を置きます。無名 PL/SQL ブロックで使用するキーワードDECLAREは、プロシージャでは使用しません。実行部では、キーワード BEGINとEXCEPTION(または END)の間に文を置きます。プロシージャの実行部には、少なくとも 1つの文が存在している必要があります。NULL文を使用すると、プレースホルダ・プロシージャを定義したり、プロシージャでアクションを実行しないように指定できます。例外処理部では、キーワード EXCEPTIONと ENDの間に例外ハンドラを置きます。

プロシージャは PL/SQL 文としてコールされます。たとえば、プロシージャraise_salaryは次のようにしてコールできます。

raise_salary(emp_id, amount);

PL/SQL ファンクションファンクションファンクションファンクションファンクションとは、値を計算するサブプログラムのことです。ファンクションとプロシージャは同じような構造を持ちますが、ファンクションの方は RETURN句を持っています。

ファンクションには多くのオプションのキーワードがあり、テーブル・ファンクションと呼ばれる特別なファンクションのクラスを宣言するために使用されます。通常、これらのキーワードは、データ・ウェアハウス・アプリケーションで大量のデータを変換する場合に使用します。

8-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 261: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ファンクション

CREATE句を使用するとスタンドアロン・ファンクションを作成できます。これは Oracleデータベース内に格納されます。CREATE FUNCTION文は、SQL*Plus またはシステム固有の動的 SQL を使用したプログラムから対話式で実行できます。

AUTHID句は、ストアド・ファンクションをその所有者(デフォルト)と現行ユーザーのどちらの権限で実行するかという点、およびスキーマ・オブジェクトへの未修飾の参照を所有者と現行ユーザーのどちらのスキーマで解決するかという点を決定します。CURRENT_USERを指定すると、デフォルトの動作を変更できます。

PARALLEL_ENABLEオプションは、ストアド・ファンクションがパラレル DML 評価のスレーブ・セッションで安全に使用されることを宣言します。メイン(ログオン)・セッションの状態が、スレーブ・セッションと共有されることはありません。スレーブ・セッションごとに固有の状態があり、セッション開始時に初期化されます。ファンクションの結果がセッション(static)変数の状態に依存しないようにしてください。さもないと、セッションごとに結果が異なる可能性があります。

ヒント DETERMINISTICは、オプティマイザが冗長なファンクション・コールを回避するのに役立ちます。ストアド・ファンクションが同じ引数で事前にコールされた場合は、オプティマイザは前の結果を使用できます。ファンクションの結果をセッション変数の状態またはスキーマ・オブジェクトに依存させないでください。さもないと、コールごとに結果が異なる可能性があります。DETERMINISTICファンクションのみが、ファンクション索引またはクエリー・リライトを使用可能にしたマテリアライズド・ビューからコールできます。詳細は、『Oracle Database SQL リファレンス』を参照してください。

AUTONOMOUS_TRANSACTIONプラグマはファンクションを自律型(独立型)としてマークするように PL/SQL コンパイラに指示します。自律型トランザクションを使用すると、メイン・トランザクションを停止し、SQL 操作を実行してその操作をコミットまたはロールバックしてから、メイン・トランザクションを再開できます。

パラメータまたはファンクション戻り値のデータ型に、NOT NULLなどで制約を課すことはできません。ただし、回避策を使用して、パラメータ型に間接的にサイズ制約を課すことができます。8-3 ページの「PL/SQL プロシージャ」を参照してください。

プロシージャと同様に、ファンクションも仕様部と本体の 2 つの部分を持ちます。ファンクションの仕様部はキーワード FUNCTIONで始め、戻り値のデータ型を指定する RETURN句で終わります。パラメータ宣言はオプションです。パラメータを取らないファンクションではカッコを書きません。

ファンクション本体は、キーワード IS(または AS)で始め、キーワード ENDで終わります。END の後には、オプションとしてファンクション名を続けることができます。ファンクション本体には、宣言部、実行部、例外処理部(オプション)の 3 つの部分があります。

宣言部では、キーワード ISと BEGINの間にローカル宣言を置きます。キーワードDECLAREは使用しません。実行部では、キーワード BEGINと EXCEPTION(または END)の間に文を置きます。ファンクションの実行部には、1 つまたは複数の RETURN文が存在している必要があります。例外処理部では、キーワード EXCEPTIONと ENDの間に例外ハンドラを置きます。

PL/SQL のサブプログラムの使用 8-5

Page 262: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ファンクション

ファンクションは、式の一部としてコールされます。

IF sal_ok(new_sal, new_title) THEN ...

RETURN 文の使用文の使用文の使用文の使用RETURN文は、サブプログラムの実行を即座に終了し、コール元に制御を戻します。サブプログラム・コールの直後の文から、実行が継続されます。(この RETURN文を、ファンクションの仕様部の中で戻り値のデータ型を指定する RETURN句と混同しないようにしてください。)

サブプログラムでは、複数の RETURN文を使用できます。サブプログラムを RETURN文で終える必要はありません。どの RETURN文を実行しても、サブプログラムは即座に終了します。

プロシージャでは、RETURN文は値を戻さないため、式を含めることはできません。RETURN 文は、プロシージャが終了する前に、コール元に制御を戻します。

ファンクションでは、RETURN文に、RETURN文の実行時に評価される式が含まれている必要があります。結果として得られる値は、RETURN句で指定された型の変数と同様の機能を持つファンクション識別子に代入されます。ファンクション balanceが、指定した銀行口座の残高をどのように戻すのかに注目してください。

FUNCTION balance (acct_id INTEGER) RETURN REAL IS acct_bal REAL;BEGIN SELECT bal INTO acct_bal FROM accts WHERE acct_no = acct_id; RETURN acct_bal;END balance;/

次の例で示すように、ファンクション RETURN文では、複雑な式も使用します。

FUNCTION compound ( years NUMBER, amount NUMBER, rate NUMBER) RETURN NUMBER ISBEGIN RETURN amount * POWER((rate / 100) + 1, years);END compound;/

ファンクションには、RETURN文へ導く少なくとも 1 つの実行パスが必要です。実行パスがない場合は、実行時に「ファンクションが値なしで戻されました」というエラーが発生します。

8-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 263: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムへのパラメータの引渡し

ネストしたネストしたネストしたネストした PL/SQL サブプログラムの宣言サブプログラムの宣言サブプログラムの宣言サブプログラムの宣言サブプログラムは、任意の PL/SQL ブロック、サブプログラムまたはパッケージの中で宣言できます。サブプログラムは、宣言部の末尾で他のすべての項目の後に置く必要があります。

サブプログラムは、コールする前に宣言する必要があります。このため、相互にコールする複数のネストしたサブプログラムを宣言することは困難になります。

前方宣言を使用すると、相互に関連したネストしたサブプログラムを宣言できます。前方宣言は、セミコロンで終わる、本体のないサブプログラム仕様部です。

仮パラメータのリストは前方宣言の中にも指定しますが、サブプログラム本体にも必要です。サブプログラム本体の位置は、前方宣言の後であればどこでもかまいませんが、同じプログラム・ユニットの中に置く必要があります。

例例例例 8-3 ネストしたサブプログラムの前方宣言ネストしたサブプログラムの前方宣言ネストしたサブプログラムの前方宣言ネストしたサブプログラムの前方宣言

DECLARE PROCEDURE proc1(arg_list); -- forward declaration PROCEDURE proc2(arg_list); -- calls proc1 PROCEDURE proc1(arg_list) IS BEGIN proc2; END; -- calls proc2BEGIN NULL;END;/

PL/SQL サブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡しサブプログラムへのパラメータの引渡しこの項では、パラメータを使用して PL/SQL サブプログラムと情報をやり取りする方法について説明します。この項の項目は、次のとおりです。

� サブプログラムの実パラメータと仮パラメータ(8-8 ページ)

� サブプログラムのパラメータの位置表記法、名前表記法または混合表記法(8-9 ページ)

� サブプログラムのパラメータのモードの指定(8-10 ページ)

� サブプログラムのパラメータのデフォルト値の使用(8-12 ページ)

PL/SQL のサブプログラムの使用 8-7

Page 264: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムへのパラメータの引渡し

サブプログラムの実パラメータと仮パラメータサブプログラムの実パラメータと仮パラメータサブプログラムの実パラメータと仮パラメータサブプログラムの実パラメータと仮パラメータサブプログラムはパラメータを使用して情報を渡します。

� サブプログラムの仕様部で宣言され、サブプログラム本体で参照される変数は、仮パラメータと呼ばれます。

� コール元のサブプログラムから渡される変数または式は、実パラメータと呼ばれます。

実パラメータと仮パラメータに別々の名前を付けることは、プログラミングの習慣として好ましいことです。

プロシージャをコールすると、実パラメータが評価され、対応する仮パラメータにその結果が代入されます。実パラメータの値を仮パラメータに代入する前に、必要に応じて PL/SQLは値のデータ型を変換します。たとえば、パラメータとして文字列を取るプロシージャに数値を渡すと、PL/SQL がパラメータを変換し、プロシージャは文字列を受け取ります。

実パラメータと、それに対応する仮パラメータは、互換性のあるデータ型を持っている必要があります。たとえば、PL/SQL は DATEデータ型と REALデータ型を変換できません。また、ドル記号などの特別な文字を含む文字列を数値に変換できません。

例例例例 8-4 仮パラメータと実パラメータ仮パラメータと実パラメータ仮パラメータと実パラメータ仮パラメータと実パラメータ

次のプロシージャは、emp_idと amountという 2 つの仮パラメータを宣言しています。

PROCEDURE raise_salary (emp_id INTEGER, amount REAL) ISBEGIN UPDATE emp SET sal = sal + amount WHERE empno = emp_id;END raise_salary;/

次のプロシージャ・コールでは、emp_numおよび amountという実パラメータが指定されています。

raise_salary(emp_num, amount);

実パラメータとして式を使用することもできます。

raise_salary(emp_num, merit + cola);

8-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 265: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムへのパラメータの引渡し

サブプログラムのパラメータの位置表記法、名前表記法または混合表記法サブプログラムのパラメータの位置表記法、名前表記法または混合表記法サブプログラムのパラメータの位置表記法、名前表記法または混合表記法サブプログラムのパラメータの位置表記法、名前表記法または混合表記法サブプログラムをコールする場合、次のいずれかの方法を使用して実パラメータを指定します。

� 位置表記法。プロシージャ内で宣言されたとおりに、同じパラメータを同じ順序で指定します。

この表記法は簡潔ですが、パラメータ(特にリテラル)を間違った順序で指定すると、不具合の検出が困難になります。プロシージャのパラメータ・リストが変更された場合は、コードを変更する必要があります。

� 名前表記法。値とともに各パラメータの名前を指定します。結合演算子は、矢印(=>)です。パラメータの順序は意味を持ちません。

この表記法はより冗長ですが、コードが読みやすくなり、メンテナンス性が向上します。たとえば、パラメータの順序が変更されたり、新しいオプション・パラメータが追加されるなど、プロシージャのパラメータ・リストが変更されたときに、コードを変更しなくてもよい場合があります。他のユーザーの API をコールするコード、または他のユーザーが使用できるように API を定義するコードでは、名前表記法を使用することは習慣として好ましいことです。

� 混合表記法。まずパラメータを位置表記法で指定し、残りのパラメータを名前表記法で指定します。

この表記法を使用して、必須パラメータの後にオプション・パラメータが続くプロシージャをコールできます。

例例例例 8-5 位置表記法、名前表記法または混合表記法でのサブプログラムのコール位置表記法、名前表記法または混合表記法でのサブプログラムのコール位置表記法、名前表記法または混合表記法でのサブプログラムのコール位置表記法、名前表記法または混合表記法でのサブプログラムのコール

DECLARE acct INTEGER := 12345; amt REAL := 500.00; PROCEDURE credit_acct (acct_no INTEGER, amount REAL) IS BEGIN NULL; END;BEGIN-- The following calls are all equivalent. credit_acct(acct, amt); -- positional credit_acct(amount => amt, acct_no => acct); -- named credit_acct(acct_no => acct, amount => amt); -- named credit_acct(acct, amount => amt); -- mixedEND;/

PL/SQL のサブプログラムの使用 8-9

Page 266: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムへのパラメータの引渡し

サブプログラムのパラメータのモードの指定サブプログラムのパラメータのモードの指定サブプログラムのパラメータのモードの指定サブプログラムのパラメータのモードの指定パラメータ・モードは、仮パラメータの動作を定義する場合に使用します。パラメータ・モードには、IN(デフォルト)、OUTおよび IN OUTの 3 つがあります。

任意のサブプログラムで任意のパラメータ・モードを使用できます。ファンクションでは、OUTモードと IN OUTモードを使用しないでください。ファンクションが複数の値を戻すようなプログラミングは、好ましくありません。また、サブプログラム専用ではない変数の値を変更するなどの副作用にも注意してください。

IN モードの使用モードの使用モードの使用モードの使用INパラメータは、コールされるサブプログラムに値を渡すために使用します。サブプログラムの中では、INパラメータは定数のように取り扱われます。値は代入できません。

定数、リテラル、初期化された変数または式を IN パラメータとして渡せます。

INパラメータはデフォルト値で初期化できます。デフォルト値は、サブプログラム・コールで INパラメータが省略された場合に使用されます。詳細は、8-12 ページの「サブプログラムのパラメータのデフォルト値の使用」を参照してください。

OUT モードの使用モードの使用モードの使用モードの使用OUTパラメータは、サブプログラムのコール元に値を戻します。サブプログラムの中では、OUTパラメータは変数のように取り扱われます。値を変更して、代入後に値を参照できます。

PROCEDURE split_name( phrase IN VARCHAR2, first OUT VARCHAR2, last OUT VARCHAR2)IS first := SUBSTR(phrase, 1, INSTR(phrase, ' ')-1); last := SUBSTR(phrase, INSTR(phrase, ' ')+1); IF first = 'John' THEN DBMS_OUTPUT.PUT_LINE('That is a common first name.'); END IF;END;/

OUTパラメータには変数を渡す必要があります。定数または式は渡せません。NOCOPYキーワード(8-12 ページの「サブプログラムのパラメータのデフォルト値の使用」を参照)を指定していない場合、または未処理例外が発生せずにサブプログラムが正常に終了した場合、以前の値は失われます。

変数と同じように、OUT仮パラメータは NULLに初期設定されます。OUT仮パラメータのデータ型は、組込みサブタイプ NATURALNや POSITIVENなどの NOT NULLとして定義されたサブタイプにはできません。そうしないと、サブプログラムをコールしたときに PL/SQLは VALUE_ERRORを呼び出します。

8-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 267: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムへのパラメータの引渡し

サブプログラムを終了する前に、すべての OUT仮パラメータに値を代入してください。そうしないと、対応する実パラメータの値は NULL になります。正常に終了した場合、PL/SQLは実パラメータに値を代入します。未処理例外が発生して終了すると、PL/SQL は実パラメータに値を代入しません。

IN OUT モードの使用モードの使用モードの使用モードの使用IN OUTパラメータは、サブプログラムに初期値を渡し、更新された値をコール元に戻します。IN OUT パラメータに値を代入したり、その値を読み取ることができます。通常、IN OUTパラメータは文字列バッファまたは数値アキュムレータであり、サブプログラム内で読み取られた後に更新されます。

IN OUT仮パラメータに対応する実パラメータは、定数や式ではなく、変数である必要があります。

サブプログラムを正常に終了した場合、PL/SQL は実パラメータに値を代入します。未処理例外が発生して終了すると、PL/SQL は実パラメータに値を代入しません。

サブプログラムのパラメータのモードの概要サブプログラムのパラメータのモードの概要サブプログラムのパラメータのモードの概要サブプログラムのパラメータのモードの概要表 8-1 に、パラメータ・モードの概要をまとめます。

表表表表 8-1 パラメータのモードパラメータのモードパラメータのモードパラメータのモード

IN OUT IN OUT

デフォルト 指定する必要がある 指定する必要がある

サブプログラムに値を渡す コール元に値を戻す サブプログラムに初期値を渡し、更新された値をコール元に戻す

仮パラメータは定数のように取り扱われる

仮パラメータは初期化されてない変数のように取り扱われる

仮パラメータは初期化された変数のように取り扱われる

仮パラメータに値を代入できない

仮パラメータには値を代入する必要がある

仮パラメータには値を代入する必要がある

実パラメータには定数、リテラル、初期化された変数または式が使用できる

実パラメータは変数である必要がある

実パラメータは変数である必要がある

実パラメータは参照方式によって渡される(その値を指すポインタが渡される)

NOCOPYが指定されていない

場合、実パラメータは値方式によって渡される(値のコピーが戻される)

NOCOPYが指定されていない

場合、実パラメータは値方式によって渡される(値のコピーがやり取りされる)

PL/SQL のサブプログラムの使用 8-11

Page 268: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラム名のオーバーロード

サブプログラムのパラメータのデフォルト値の使用サブプログラムのパラメータのデフォルト値の使用サブプログラムのパラメータのデフォルト値の使用サブプログラムのパラメータのデフォルト値の使用INパラメータをデフォルト値に初期化することで、サブプログラムに様々な数の実パラメータを渡し、省略したパラメータにはデフォルト値を指定できます。さらに、サブプログラムへのコールを個々に変更しなくても、仮パラメータを新しく追加できます。

例例例例 8-6 デフォルトのパラメータ値を使用したプロシージャデフォルトのパラメータ値を使用したプロシージャデフォルトのパラメータ値を使用したプロシージャデフォルトのパラメータ値を使用したプロシージャ

PROCEDURE create_dept ( new_dname VARCHAR2 DEFAULT 'TEMP', new_loc VARCHAR2 DEFAULT 'TEMP') ISBEGIN NULL;END;/

パラメータが省略されると、対応する仮パラメータのデフォルト値が使用されます。次に示すような create_deptのコールを考えてみます。

create_dept; -- Same as create_dept('TEMP','TEMP');create_dept('SALES'); -- Same as create_dept('SALES','TEMP');create_dept('SALES', 'NY');

実パラメータを省略して、仮パラメータを 1 つスキップすることはできません。 初のパラメータを省略して 2 番目のパラメータを指定するには、名前表記法を使用します。

create_dept(new_loc => 'NEW YORK');

実パラメータを省略して、初期化されていない仮パラメータに NULL を代入することはできません。明示的に NULL を渡すか、または宣言部でデフォルト値に NULLを指定します。

サブプログラム名のオーバーロードサブプログラム名のオーバーロードサブプログラム名のオーバーロードサブプログラム名のオーバーロードPL/SQL ではサブプログラム名と型の順序をオーバーロードオーバーロードオーバーロードオーバーロードできます。仮パラメータの数、順序またはデータ型が異なっていれば、同じ名前を複数のサブプログラムで使用できます。

次のように宣言された 2 つの索引付き表の 初の n 行を初期化するとします。

DECLARE TYPE DateTabTyp IS TABLE OF DATE INDEX BY BINARY_INTEGER; TYPE RealTabTyp IS TABLE OF REAL INDEX BY BINARY_INTEGER; hiredate_tab DateTabTyp; sal_tab RealTabTyp;BEGIN NULL;END;/

8-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 269: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラム名のオーバーロード

ある種類のコレクションを初期化するプロシージャを記述するとします。

PROCEDURE initialize (tab OUT DateTabTyp, n INTEGER) ISBEGIN FOR i IN 1..n LOOP tab(i) := SYSDATE; END LOOP;END initialize;/

別の種類のコレクションを初期化するプロシージャも記述するとします。

PROCEDURE initialize (tab OUT RealTabTyp, n INTEGER) ISBEGIN FOR i IN 1..n LOOP tab(i) := 0.0; END LOOP;END initialize;/

この 2 つのプロシージャは同じ処理を実行しているため、同じ名前を与えるのが論理的です。

オーバーロードされるこの 2 つの initializeプロシージャは、同じブロック、サブプログラム、パッケージまたはオブジェクト型の中に置くことができます。PL/SQL は仮パラメータをチェックして、どちらのプロシージャをコールするかを判断します。次の例でPL/SQL が使用する initializeのバージョンは、プロシージャを DateTabTypパラメータまたは RealTabTypパラメータのどちらでコールするかによって異なります。

DECLARE TYPE DateTabTyp IS TABLE OF DATE INDEX BY BINARY_INTEGER; TYPE RealTabTyp IS TABLE OF REAL INDEX BY BINARY_INTEGER; hiredate_tab DateTabTyp; comm_tab RealTabTyp; indx BINARY_INTEGER; PROCEDURE initialize (tab OUT DateTabTyp, n INTEGER) IS BEGIN NULL; END; PROCEDURE initialize (tab OUT RealTabTyp, n INTEGER) IS BEGIN NULL; END;BEGIN indx := 50; initialize(hiredate_tab, indx); -- calls first version initialize(comm_tab, indx); -- calls second versionEND;/

PL/SQL のサブプログラムの使用 8-13

Page 270: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラム名のオーバーロード

数値型のオーバーロードのガイドライン数値型のオーバーロードのガイドライン数値型のオーバーロードのガイドライン数値型のオーバーロードのガイドライン2 つのサブプログラムの仮パラメータの違いが数値データ型のみの場合、それらのサブプログラムはオーバーロードできます。この手法は、ファンクションの複数のバージョンが同じ名前を使用し、それぞれが異なる数値型を受け取る数値演算 API を記述する場合に有効です。たとえば、BINARY_FLOATを受け取るファンクションはより高速で、BINARY_DOUBLEを受け取るファンクションは精度がより高くなる場合があります。

オーバーロードされたサブプログラムにパラメータを渡す場合、次のことに注意して、問題または予期しない結果を回避します。

� 予期されるすべてのパラメータ・セットで、目的のバージョンのサブプログラムがコールされることを確認します。たとえば、オーバーロードされるファンクションがBINARY_FLOATおよび BINARY_DOUBLEを受け取る場合、「5.0」のような VARCHAR2リテラルを渡すと、どちらのファンクションがコールされるかを確認します。

� 数値リテラルを修飾したり、変換ファンクションを使用して、目的のパラメータ型を明示します。たとえば、5.0f(BINARY_FLOAT)、5.0d(BINARY_DOUBLE)のようなリテラル、または TO_BINARY_FLOAT()、TO_BINARY_DOUBLE()、TO_NUMBER()のような変換ファンクションを使用します。

PL/SQL が一致する数値パラメータを検索する順序は、 初に PLS_INTEGERまたはBINARY_INTEGER、次に NUMBER、次に BINARY_FLOAT、 後に BINARY_DOUBLEです。指定されたパラメータに 初に一致したオーバーロードされるサブプログラムが使用されます。VARCHAR2値は、NUMBER、BINARY_FLOATまたは BINARY_DOUBLEパラメータに一致します。

たとえば、1 つのパラメータを受け取る SQRTファンクションについて考えます。NUMBER、BINARY_FLOATまたは BINARY_DOUBLEパラメータを受け取るオーバーロードされるファンクションがあるとします。PLS_INTEGERパラメータを渡した場合、(前述の順序を使用すると) 初に一致してオーバーロードされるファンクションは、 も低速である可能性が高い NUMBERパラメータのファンクションです。より高速なバージョンを使用するには、TO_BINARY_FLOATまたは TO_BINARY_DOUBLEファンクションを使用して、パラメータを適切なデータ型に変換します。

次に、同じ型の 2 つのパラメータを受け取る ATAN2ファンクションについて考えます。同じ型の 2 つのパラメータを渡した場合、どのオーバーロードされるバージョンが使用されるかは、前述の例と同じ規則から決定されます。異なる型のパラメータを渡した場合(たとえば、1 つが PLS_INTEGERで、1 つが BINARY_FLOATの場合)、PL/SQL は、両方のパラメータで「より高度な」型が使用されている場合に一致するものを検索します。この例では、2 つの BINARY_FLOATパラメータを受け取るバージョンの ATAN2が使用されます。PLS_INTEGERパラメータは、「上位」変換されます。

8-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 271: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのコールの解決方法

「上位」変換は、さらに複雑な状況でも適用されます。たとえば、異なる型の 2 つのパラメータを受け取る複雑なファンクションがあるとします。オーバーロードされるバージョンの 1 つが、PLS_INTEGERパラメータおよび BINARY_FLOATパラメータを受け取るとします。別のオーバーロードされるバージョンが、NUMBERパラメータおよび BINARY_DOUBLEパラメータを受け取るとします。2 つの NUMBERパラメータを渡してこのプロシージャ名をコールします。PL/SQL はまず「上位」検索し、2 つ目のパラメータが BINARY_FLOATのオーバーロードされるバージョンを検出します。このパラメータは、他方のオーバーロードされるバージョンの BINARY_DOUBLEパラメータよりも一致度が高いため、次に PL/SQLは「下位」検索し、1 つ目の NUMBERパラメータを PLS_INTEGERに変換します。

オーバーロードの制限オーバーロードの制限オーバーロードの制限オーバーロードの制限オーバーロードできるのは、ローカル・サブプログラム、パッケージ・サブプログラムまたは型の順序のみです。スタンドアロン・サブプログラムはオーバーロードできません。

サブプログラムの仮パラメータの違いが名前またはパラメータ・モードのみの場合は、2 つのサブプログラムをオーバーロードできません。たとえば、次の 2 つのプロシージャはオーバーロードできません。

DECLARE PROCEDURE reconcile (acct_no IN INTEGER) IS BEGIN NULL; END; PROCEDURE reconcile (acct_no OUT INTEGER) IS BEGIN NULL; END;/

サブプログラムのパラメータの違いがサブタイプのみの場合は、サブプログラムをオーバーロードできません。たとえば、INTEGERパラメータを受け取るプロシージャと REALパラメータを受け取るプロシージャは、オーバーロードできません。INTEGERと REALは両方とも NUMBERのサブタイプであり、同じファミリに属すためです。

戻り値のデータ型のみが異なる 2 つのファンクションは、その型のファミリが異なっている場合でも、オーバーロードできません。たとえば、BOOLEANを戻すファンクションとINTEGERを戻すファンクションは、オーバーロードできません。

サブプログラムのコールの解決方法サブプログラムのコールの解決方法サブプログラムのコールの解決方法サブプログラムのコールの解決方法図 8-1 に、PL/SQL コンパイラがサブプログラム・コールを解決する方法を示します。コンパイラがプロシージャ・コールまたはファンクション・コールを発見すると、そのコールに合う宣言を探します。コンパイラはまず現在の有効範囲を検索し、必要ならば外側の有効範囲を順に検索します。コールされたサブプログラムの名前と同じ名前のサブプログラム宣言が 1 つ以上見つかると、コンパイラはさらに厳密に検索します。

PL/SQL のサブプログラムの使用 8-15

Page 272: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのコールの解決方法

同じ有効範囲のレベルに同じような名前のサブプログラムが存在する場合は、コールを解決するために、コンパイラは実パラメータと仮パラメータが正確に一致するものを発見する必要があります。パラメータは、(いくつかの仮パラメータにデフォルト値が代入されている場合を除き)数、順序およびデータ型が一致している必要があります。一致するものが見つからなかった場合、または一致するものが複数見つかった場合、コンパイラはセマンティック・エラーを生成します。

次の例では、ファンクション reconcileから外側のプロシージャ swapをコールしています。現在の有効範囲の中にある swapの宣言が、いずれもプロシージャ・コールと一致しないために、コンパイラはエラーを生成します。

PROCEDURE swap (n1 NUMBER, n2 NUMBER) IS num1 NUMBER; num2 NUMBER; FUNCTION balance (...) RETURN REAL IS PROCEDURE swap (d1 DATE, d2 DATE) IS BEGIN NULL; END; PROCEDURE swap (b1 BOOLEAN, b2 BOOLEAN) IS BEGIN NULL; END; BEGIN swap(num1, num2); RETURN ... END balance;BEGIN NULL; END;/

8-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 273: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのコールの解決方法

図図図図 8-1 PL/SQL コンパイラによるコールの解決方法コンパイラによるコールの解決方法コンパイラによるコールの解決方法コンパイラによるコールの解決方法

PL/SQL のサブプログラムの使用 8-17

Page 274: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのコールの解決方法

オーバーロードと継承の相互作用オーバーロードと継承の相互作用オーバーロードと継承の相互作用オーバーロードと継承の相互作用オーバーロード・アルゴリズムでは、スーパータイプである仮パラメータのかわりにサブタイプの値を使用できます。この機能は代替性代替性代替性代替性と呼ばれます。オーバーロードされるプロシージャの複数のインスタンスがプロシージャ・コールと一致する場合は、どのプロシージャがコールされるかを判断するために次の規則が適用されます。

オーバーロードされる各プロシージャのシグネチャの違いが、一部のパラメータが同じスーパータイプ / サブタイプ階層のオブジェクト型であるということのみの場合は、 大一致のものが使用されます。 大一致とは、すべてのパラメータがオーバーロードされる他のインスタンスと少なくとも同程度に近く、少なくとも 1 つのパラメータが近い場合を指します。この近さは、サブタイプとスーパータイプ間の継承の深さによって決まります。

オーバーロードされる 2 つのインスタンスが一致し、オーバーロードされる一方のプロシージャ内の一部の引数の型が他のインスタンス内よりも実引数に近いと、セマンティック・エラーが発生します。

また、一部のパラメータの位置がオブジェクト型階層内で異なり、他のパラメータのデータ型が異なる場合も、暗黙的な変換が必要になるため、セマンティック・エラーが発生します。

たとえば、3 つのレベルを持つ型の階層を作成するとします。

CREATE TYPE super_t AS object (n NUMBER) NOT final;CREATE OR replace TYPE sub_t under super_t (n2 NUMBER) NOT final;CREATE OR replace TYPE final_t under sub_t (n3 NUMBER);

あるファンクションについて、オーバーロードされるインスタンスを 2 つ宣言します。両者の引数の型の違いは、この型階層内での位置のみです。

CREATE PACKAGE p IS FUNCTION foo (arg super_t) RETURN NUMBER; FUNCTION foo (arg sub_t) RETURN NUMBER;END;/CREATE PACKAGE BODY p IS FUNCTION foo (arg super_t) RETURN NUMBER IS BEGIN RETURN 1; END; FUNCTION foo (arg sub_t) RETURN NUMBER IS BEGIN RETURN 2; END;END;/

8-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 275: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのコールの解決方法

final_t型の変数を宣言してから、オーバーロードされるファンクションをコールします。ファンクションのインスタンスのうち実行されるのは、sub_tパラメータを受け入れるインスタンスです。これは、その型が階層内で super_tよりも final_tに近いためです。

set serveroutput ondeclarev final_t := final_t(1,2,3);begin dbms_output.put_line(p.foo(v));end;/

前述の例では、コールするインスタンスはコンパイル時に選択されます。次の例では、この選択が動的に行われます。

CREATE TYPE super_t2 AS object (n NUMBER, MEMBER FUNCTION foo RETURN NUMBER) NOT final;/CREATE TYPE BODY super_t2 AS MEMBER FUNCTION foo RETURN NUMBER IS BEGIN RETURN 1; END; END;/CREATE OR replace TYPE sub_t2 under super_t2 (n2 NUMBER, OVERRIDING MEMBER FUNCTION foo RETURN NUMBER) NOT final;/CREATE TYPE BODY sub_t2 AS OVERRIDING MEMBER FUNCTION foo RETURN NUMBER IS BEGIN RETURN 2;END;END;/CREATE OR replace TYPE final_t2 under sub_t2 (n3 NUMBER);/

vを super_t2のインスタンスとして宣言しますが、そこに sub_t2の値を代入するために、ファンクションの適切なインスタンスがコールされます。この機能は動的ディスパッチ動的ディスパッチ動的ディスパッチ動的ディスパッチと呼ばれます。

set serveroutput ondeclare v super_t2 := final_t2(1,2,3);begin dbms_output.put_line(v.foo);end;/

PL/SQL のサブプログラムの使用 8-19

Page 276: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(実行者権限と定義者権限の使用(AUTHID 句)句)句)句)デフォルトでは、ストアド・プロシージャおよび SQL メソッドは、現行ユーザーの権限ではなく所有者の権限で実行します。このような定義者権限サブプログラムは、サブプログラムが存在するスキーマにバインドされ、同じスキーマのオブジェクトを名前の修飾なしに参照できます。たとえば、スキーマ SCOTTと BLAKEの両方に dept表がある場合、SCOTTが所有するプロシージャは、SCOTT.DEPTのかわりに deptを使用してその表を参照できます。ユーザー BLAKEが SCOTTのプロシージャをコールした場合、プロシージャは SCOTTが所有する dept表にアクセスします。

同じプロシージャを両方のスキーマでコンパイルする場合、SQL*Plus でスキーマ名を変数として定義し、&schema..deptのように表を参照できます。このコードは移植性がありますが、コードを変更した場合はそれぞれのスキーマで再コンパイルする必要があります。

よりメンテナンス性の高い方法は、AUTHID句を使用することです。これによって、ストアド・プロシージャおよび SQL メソッドをコール元のユーザーの権限とスキーマ・コンテキストで実行できます。プロシージャのインスタンスを 1 つ作成し、多くのユーザーがそのプロシージャをコールしてユーザー自身のデータにアクセスできます。

このような実行者権限サブプログラムは、特定のスキーマにバインドされません。たとえば、次に示すプロシージャ create_deptは、コール元のユーザーの権限で実行され、そのユーザーの dept表に行を挿入します。

CREATE PROCEDURE create_dept ( my_deptno NUMBER, my_dname VARCHAR2, my_loc VARCHAR2) AUTHID CURRENT_USER ASBEGIN INSERT INTO dept VALUES (my_deptno, my_dname, my_loc);END;/

実行者権限のメリット実行者権限のメリット実行者権限のメリット実行者権限のメリット実行者権限サブプログラムを使用すると、コードを再利用し、アプリケーション・ロジックを集中化できます。これは、異なるスキーマの同じ名前の表にデータを格納するアプリケーションで特に便利です。1 つのインスタンス内のすべてのスキーマは、集中管理された 1 つのスキーマが所有するプロシージャをコールできます。異なるインスタンスのスキーマから、データベース・リンクを使用して、集中管理されたプロシージャをコールすることもできます。

ストアド・プロシージャを使用して売上を分析する会社の場合を考えてみます。この会社に複数のスキーマがあり、それぞれによく似た SALES表がある場合、通常、各スキーマにストアド・プロシージャのコピーが必要になります。

8-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 277: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

この問題を解決するには、ストアド・プロシージャの実行者権限バージョンを集中管理されたスキーマにインストールします。これによって、他のすべてのスキーマから同じプロシージャをコールでき、プロシージャはそれぞれの場合に応じて適切な SALES表を問い合せます。

実行者権限サブプログラムから、機密データを含むテーブルへの問合せまたは更新を行う定義者権限サブプログラムをコールすることによって、機密データへのアクセスを制限できます。複数のユーザーが実行者権限サブプログラムをコールできますが、機密データに直接アクセスできません。

AUTHID 句によるサブプログラムの権限の指定句によるサブプログラムの権限の指定句によるサブプログラムの権限の指定句によるサブプログラムの権限の指定実行者権限を実装するには、AUTHID句を使用して、サブプログラムを所有者と現行ユーザーのどちらの権限で実行するかを指定します。またこの句は、外部参照(サブプログラムの外側のオブジェクトへの参照)が所有者と現行ユーザーのどちらのスキーマで解決されるかも指定します。

AUTHID句は、スタンドアロン・サブプログラム、パッケージ仕様部またはオブジェクト型仕様部のヘッダーでのみ使用できます。CREATE FUNCTION文、CREATE PROCEDURE文、CREATE PACKAGE文または CREATE TYPE文では、宣言部の先頭の ISまたは ASの直前に、AUTHID CURRENT_USERまたは AUTHID DEFINERのいずれかを含めることができます。

DEFINERはデフォルトのオプションです。パッケージまたはオブジェクト型では、AUTHID句はすべてのサブプログラムに適用されます。

注意注意注意注意 : 提供されている PL/SQL パッケージの大部分(DBMS_LOB、DBMS_PIPE、DBMS_ROWID、DBMS_SQLおよび UTL_REF)は、実行者権限パッケージです。

サブプログラム実行中の現行ユーザーサブプログラム実行中の現行ユーザーサブプログラム実行中の現行ユーザーサブプログラム実行中の現行ユーザー一連のコールで制御が実行者権限サブプログラム内にある場合は常に、現行ユーザーとはセッション・ユーザーを指します。定義者権限サブプログラムがコールされた場合は、そのサブプログラムの所有者が現行ユーザーになります。新しいサブプログラムがコールされたり、サブプログラムが終了すると、現行ユーザーは変更されます。

USER_USERSデータ・ディクショナリ・ビューを参照すると、いつでも現行ユーザーを確認できます。実行者権限サブプログラム内では、このビューの値は USER組込みファンクションの値と異なる場合があります。このファンクションは、常にセッション・ユーザーの名前を戻します。

PL/SQL のサブプログラムの使用 8-21

Page 278: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

実行者権限サブプログラムでの外部参照の解決実行者権限サブプログラムでの外部参照の解決実行者権限サブプログラムでの外部参照の解決実行者権限サブプログラムでの外部参照の解決AUTHID CURRENT_USERを指定すると、実行時に現行ユーザーの権限がチェックされ、外部参照は現行ユーザーのスキーマで解決されます。ただし、これは次の文の外部参照にのみ適用されます。

� SELECT、INSERT、UPDATEおよび DELETE DML 文

� LOCK TABLEトランザクション制御文

� OPENおよび OPEN-FORカーソル制御文

� EXECUTE IMMEDIATEおよび OPEN-FOR-USING動的 SQL 文

� DBMS_SQL.PARSE()を使用して解析された SQL 文

それ以外の文の場合は、コンパイル時に所有者の権限がチェックされ、外部参照は所有者のスキーマで解決されます。たとえば、次の代入文はパッケージ・ファンクション balanceを参照します。この外部参照はプロシージャ reconcileの所有者のスキーマで解決されます。

CREATE PROCEDURE reconcile (acc_id IN INTEGER) AUTHID CURRENT_USER AS bal NUMBER;BEGIN bal := bank_ops.balance(acct_id); ...END;/

実行者権限サブプログラムでのテンプレート・オブジェクトの必要性実行者権限サブプログラムでのテンプレート・オブジェクトの必要性実行者権限サブプログラムでのテンプレート・オブジェクトの必要性実行者権限サブプログラムでのテンプレート・オブジェクトの必要性PL/SQL コンパイラは、表および他のオブジェクトへのすべての参照をコンパイル時に解決する必要があります。実行者権限サブプログラムの所有者は、同じスキーマ内に正しい名前と列のオブジェクトを持つ必要があります。オブジェクトには、データが存在していなくてもかまいません。実行時に、コール元のスキーマ内の対応するオブジェクトは、一致する定義を持っている必要があります。そうでない場合、エラーまたは予期しない結果(コール元のスキーマには存在するがサブプログラムを含むスキーマには存在しない表の列が無視されるなど)が発生します。

実行者権限サブプログラムでのデフォルトの名前解決のオーバーライド実行者権限サブプログラムでのデフォルトの名前解決のオーバーライド実行者権限サブプログラムでのデフォルトの名前解決のオーバーライド実行者権限サブプログラムでのデフォルトの名前解決のオーバーライドコール元のスキーマではなく特定のスキーマを参照するために、未修飾の名前が必要な場合があります。実行者権限サブプログラムと同じスキーマ内で、CREATE SYNONYM文を使用して、表、プロシージャ、ファンクションまたはその他のオブジェクトのパブリック・シノニムを作成します。

CREATE PUBLIC SYNONYM emp FOR hr.employees;

8-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 279: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

実行者権限サブプログラムがこの名前を参照している場合、サブプログラム自身のスキーマ内のシノニムと一致し、指定されたスキーマ内のオブジェクトへ解決されます。コール元のスキーマに同じ名前のスキーマ・オブジェクトまたはプライベート・シノニムがすでに存在する場合、この手法は使用できません。その場合は、実行者権限サブプログラムで参照を完全修飾する必要があります。

実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与サブプログラムを直接コールするには、ユーザーはそのサブプログラムに対して EXECUTE権限を持っている必要があります。権限を付与することで、ユーザーに次のことを許可します。

� サブプログラムの直接のコール

� サブプログラムをコールするファンクションおよびプロシージャのコンパイル

現行ユーザーのスキーマで解決される外部参照の場合(DML 文内など)、現行ユーザーはサブプログラムが参照するスキーマ・オブジェクトへのアクセスに必要な権限を持っている必要があります。その他すべての外部参照(ファンクション・コールなど)の場合は、所有者の権限がコンパイル時にチェックされ、実行時にはチェックされません。

定義者権限サブプログラムは、実行者にかかわらず、その所有者のセキュリティ・ドメインで作動します。所有者はサブプログラムが参照するスキーマ・オブジェクトへのアクセスに必要な権限を持っている必要があります。

複数のサブプログラムからなるプログラムを作成できます。定義者権限を持つものと実行者権限を持つものとを混在させることもできます。この場合、EXECUTE権限を使用して、プログラムのエントリ・ポイントを制限できます。これによって、エントリ・ポイント・サブプログラムのユーザーは他のサブプログラムを直接ではなく間接的に実行できます。

実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与実行者権限サブプログラムに対する権限の付与 : 例例例例ユーザー UTILが、サブプログラム FFTに対する EXECUTE権限を、ユーザー APPに付与するとします。

GRANT EXECUTE ON util.fft TO app;

ユーザー APPは、サブプログラム FFTをコールするファンクションおよびプロシージャをコンパイルできるようになります。実行時には、このコールについての権限チェックは行われません。図 8-2 に示すように、ユーザー UTILは、FFTを間接的にコールするユーザーに1 人ずつ EXECUTE権限を付与する必要はありません。

サブプログラム util.fftは実行者権限サブプログラム app.entryからのみ直接コールされるため、ユーザー utilは、EXECUTE権限をユーザー APPにのみ付与する必要があります。UTIL.FFTを実行すると、その現行ユーザーは APP、SCOTTまたは BLAKEになります。SCOTTおよび BLAKEが EXECUTE権限を付与されていない場合も同様です。

PL/SQL のサブプログラムの使用 8-23

Page 280: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

図図図図 8-2 実行者権限サブプログラムへの間接コール実行者権限サブプログラムへの間接コール実行者権限サブプログラムへの間接コール実行者権限サブプログラムへの間接コール

実行者権限サブプログラムでのロールの使用実行者権限サブプログラムでのロールの使用実行者権限サブプログラムでのロールの使用実行者権限サブプログラムでのロールの使用サブプログラムでのロールの使用は、定義者権限と実行者権限のどちらで実行するかによって異なります。定義者権限サブプログラムでは、すべてのロールが使用禁止になります。ロールは権限チェックには使用されません。また、ロールを設定することはできません。

実行者権限サブプログラムでは、ロールは使用可能になります(サブプログラムが定義者権限サブプログラムによって直接または間接的にコールされた場合を除きます)。ロールは権限チェックに使用されます。また、システム固有の動的 SQL を使用してセッションにロールを設定できます。ただし、ロールはコンパイル時ではなく実行時に適用されるため、ロールを使用してテンプレート・オブジェクトに権限を付与することはできません。

実行者権限サブプログラムでのビューおよびデータベース・トリガーの使用実行者権限サブプログラムでのビューおよびデータベース・トリガーの使用実行者権限サブプログラムでのビューおよびデータベース・トリガーの使用実行者権限サブプログラムでのビューおよびデータベース・トリガーの使用ビュー式内で実行される実行者権限サブプログラムの場合は、ビューを問い合せているスキーマではなく、ビューを作成したスキーマが現行ユーザーとみなされます。

この規則は、データベース・トリガーにも適用されます。

8-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 281: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

実行者権限サブプログラムでのデータベース・リンクの使用実行者権限サブプログラムでのデータベース・リンクの使用実行者権限サブプログラムでのデータベース・リンクの使用実行者権限サブプログラムでのデータベース・リンクの使用データベース・リンクを作成して、実行者権限を使用できます。

CREATE DATABASE LINK link_name CONNECT TO CURRENT_USER USING connect_string;

現行ユーザー・リンクでは、そのユーザー権限を持つ別のユーザーとしてリモート・データベースに接続できます。接続するために、Oracle では現行ユーザーのユーザー名を使用します(実行者はグローバル・ユーザーである必要があります)。ユーザー BLAKEが所有する実行者権限サブプログラムが、次のデータベース・リンクを参照するとします。グローバル・ユーザー SCOTTがそのサブプログラムをコールしていれば、現行ユーザーであるユーザーSCOTTでデータベース Dallas に接続します。

CREATE DATABASE LINK dallas CONNECT TO CURRENT_USER USING ...

定義者権限サブプログラムの場合、現行ユーザーは BLAKEであり、サブプログラムはグローバル・ユーザー BLAKEでデータベース Dallas に接続します。

実行者権限サブプログラムでのオブジェクト型の使用実行者権限サブプログラムでのオブジェクト型の使用実行者権限サブプログラムでのオブジェクト型の使用実行者権限サブプログラムでのオブジェクト型の使用任意のスキーマで使用するオブジェクト型を定義するために、AUTHID CURRENT_USER句を指定します。(オブジェクト型の詳細は、第 12 章「PL/SQL のオブジェクト型の使用」を参照。)ユーザー BLAKEが次のようにオブジェクト型を作成するとします。

CREATE TYPE Num AUTHID CURRENT_USER AS OBJECT ( x NUMBER, STATIC PROCEDURE new_num ( n NUMBER, schema_name VARCHAR2, table_name VARCHAR2));/

CREATE TYPE BODY Num AS STATIC PROCEDURE new_num ( n NUMBER, schema_name VARCHAR2, table_name VARCHAR2) IS sql_stmt VARCHAR2(200); BEGIN sql_stmt := 'INSERT INTO ' || schema_name || '.' || table_name || ' VALUES (blake.Num(:1))'; EXECUTE IMMEDIATE sql_stmt USING n; END;END;/

次にユーザー BLAKEは、オブジェクト型 Numに対する EXECUTE権限を、ユーザー SCOTTに付与します。

GRANT EXECUTE ON Num TO scott;

PL/SQL のサブプログラムの使用 8-25

Page 282: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

実行者権限と定義者権限の使用(AUTHID 句)

後に、ユーザー SCOTTは、Num型のオブジェクトを格納するためにオブジェクト表を作成し、次にプロシージャ new_numをコールして、その表にデータを入れます。

CONNECT scott/tiger;CREATE TABLE num_tab OF blake.Num;/BEGIN blake.Num.new_num(1001, 'scott', 'num_tab'); blake.Num.new_num(1002, 'scott', 'num_tab'); blake.Num.new_num(1003, 'scott', 'num_tab');END;/

コールは成功しました。これはプロシージャがその所有者(BLAKE)の権限ではなく現行ユーザー(SCOTT)の権限で実行されたためです。

オブジェクト型階層内のサブタイプには、次の規則が適用されます。

� サブタイプで AUTHID句が明示的に指定されていない場合は、スーパータイプのAUTHIDを継承します。

� サブタイプで AUTHID句が指定されている場合、その AUTHIDがスーパータイプのAUTHIDと一致する必要があります。また、AUTHIDが DEFINERの場合は、スーパータイプとサブタイプの両方が同じスキーマに作成されている必要があります。

実行者権限のインスタンス・メソッドのコール実行者権限のインスタンス・メソッドのコール実行者権限のインスタンス・メソッドのコール実行者権限のインスタンス・メソッドのコール実行者権限インスタンス・メソッドは、インスタンスの作成者ではなく、実行者の権限で実行します。Personが実行者権限オブジェクト型で、ユーザー SCOTTが、型 Personのオブジェクトである p1を作成するとします。ユーザー BLAKEが、オブジェクト p1で操作を行うためのインスタンス・メソッド change_jobをコールする場合、メソッドの現行ユーザーは、SCOTTではなく、BLAKEです。次の例を考えます。

-- user blake creates a definer-rights procedureCREATE PROCEDURE reassign (p Person, new_job VARCHAR2) ASBEGIN -- user blake calls method change_job, so the -- method executes with the privileges of blake p.change_job(new_job); ...END;/

-- user scott passes a Person object to the procedureDECLARE p1 Person;BEGIN p1 := Person(...);

8-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 283: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

外部サブプログラムのコール

blake.reassign(p1, 'CLERK'); ...END;/

PL/SQL での再帰の使用での再帰の使用での再帰の使用での再帰の使用再帰はアルゴリズムの設計を単純化する強力な手法です。一般に、再帰とは自己参照を意味します。再帰的な数列の個々の項は、それ以前の項に計算式を適用することで得られます。フィボナッチ数列(0, 1, 1, 2, 3, 5, 8, 13, 21, ...)がその一例です。この数列では、2 番以降の各項が、すぐ前の 2 つの項の合計になっています。

再帰定義では、それ自身をさらに単純なバージョンに定義します。n の階乗(n!、1 ~ n のすべての整数の積)の定義を考えてみます。

n! = n * (n - 1)!

再帰的サブプログラム再帰的サブプログラム再帰的サブプログラム再帰的サブプログラム再帰的サブプログラムとは、自分自身をコールするサブプログラムのことです。再帰的コールが行われるたびに、パラメータ、変数、カーソル、例外など、そのサブプログラムで宣言されているすべての項目の新しいインスタンスが作成されます。また、再帰を繰り返して進む過程の各レベルで、SQL 文の新しいインスタンスが作成されます。

再帰的コールを入れる位置には注意してください。カーソル FORループの中や、OPEN文とCLOSE文の間に入れると、コールのたびに新しいカーソルがオープンされます。これによって、Oracle の OPEN_CURSORS初期化パラメータによって設定された限界を超える場合があります。

再帰的サブプログラムには、再帰的コールへ導くパスとそうではないパスの、少なくとも 2つのパスが必要です。終了条件へ導くパスが少なくとも 1 つは必要だということです。そうでない場合、メモリーが足りなくなり、PL/SQL によって事前定義の例外 STORAGE_ERRORが呼び出されるまで、再帰が続きます。

外部サブプログラムのコール外部サブプログラムのコール外部サブプログラムのコール外部サブプログラムのコールPL/SQL は強力かつ柔軟な言語ですが、他の言語を使用した方が容易に実行できる作業もあります。C のような低レベルの言語は非常に高速です。Java のような広く使用されている言語には、共通の設計パターン用の再利用可能なライブラリが存在します。

PL/SQL のコール仕様を使用すると、別の言語で記述された外部サブプログラムを起動して、それらの機能およびライブラリを PL/SQL から使用できます。

たとえば、Java ストアド・プロシージャは、任意の PL/SQL ブロック、サブプログラムまたはパッケージからコールできます。データベースに次の Java クラスを格納するとします。

PL/SQL のサブプログラムの使用 8-27

Page 284: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

外部サブプログラムのコール

import java.sql.*;import oracle.jdbc.driver.*;public class Adjuster { public static void raiseSalary (int empNo, float percent) throws SQLException { Connection conn = new OracleDriver().defaultConnection(); String sql = "UPDATE emp SET sal = sal * ? WHERE empno = ?"; try { PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setFloat(1, (1 + percent / 100)); pstmt.setInt(2, empNo); pstmt.executeUpdate(); pstmt.close(); } catch (SQLException e) {System.err.println(e.getMessage());} }}

クラス Adjusterには、従業員の給与を指定のパーセンテージ分のみ増やすメソッドがあります。raiseSalaryは voidメソッドであるため、次のコール仕様を使用してプロシージャとして発行します。

CREATE PROCEDURE raise_salary (empno NUMBER, pct NUMBER)AS LANGUAGE JAVANAME 'Adjuster.raiseSalary(int, float)';

プロシージャ raise_salaryを無名 PL/SQL ブロックからコールできます。

DECLARE emp_id NUMBER; percent NUMBER;BEGIN -- get values for emp_id and percent raise_salary(emp_id, percent); -- call external subprogramEND;/

外部 C サブプログラムは、組込みシステムとのインタフェース、技術的な分野の問題解決、データの分析、リアルタイムのデバイスや処理の制御に使用します。外部 C サブプログラムを使用すると、データベース・サーバーの機能性を拡張し、計算専用プログラムをクライアントからサーバーに移動できます。サーバーの方が高速に処理できます。

Java ストアド・プロシージャの詳細は、『Oracle Database Java 開発者ガイド』を参照してください。外部 C サブプログラムの詳細は、『Oracle Database アプリケーション開発者ガイド- 基礎編』を参照してください。

8-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 285: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL サブプログラムの副作用の制御

PL/SQL Server Pages((((PSP)を使用した動的)を使用した動的)を使用した動的)を使用した動的 Web ページの作成ページの作成ページの作成ページの作成PL/SQL Server Pages(PSP)を使用すると、Web ページを動的コンテンツで開発できます。これは、Web ページ用に HTML コードを一度に 1 行ずつ書き出すストアド・プロシージャをコーディングする方法の代替手段です。

特殊なタグを使用すると、PL/SQL スクリプトを HTML ソース・コードに埋め込むことができます。スクリプトは、ページがブラウザなどの Web クライアントによって要求された時に実行されます。スクリプトは、パラメータ、データベースへの問合せまたは更新を受け入れる事が可能で、結果を示すカスタマイズ済のページを表示できます。

開発中、PSP はページ・レイアウト用の静的部分およびコンテンツ用の動的部分を持つテンプレートのように動作できます。任意の HTML オーサリング・ツールを使用してレイアウトを設計できます。プレースホルダは動的コンテンツ用に残します。次に、コンテンツを生成する PL/SQL スクリプトを作成できます。終了した後、作成した PSP ファイルをストアド・プロシージャとして単にデータベースにロードします。

PSP の作成と使用の詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

PL/SQL サブプログラムの副作用の制御サブプログラムの副作用の制御サブプログラムの副作用の制御サブプログラムの副作用の制御ストアド・ファンクション(およびそのファンクションによってコールされるサブプログラム)は、次に示す副作用を制御するための純正規則に従っている場合にのみ、SQL 文からコールできます。

� SELECT文またはパラレル化 INSERT文、UPDATE文または DELETE文からコールされた場合、ファンクションはデータベース表を変更できません。

� INSERT文、UPDATE文または DELETE文からコールされた場合、ファンクションは、その文によって変更されたデータベース表の問合せや変更はできません。

� SELECT文、INSERT文、UPDATE文または DELETE文からコールされた場合、ファンクションは SQL トランザクション制御文(COMMITなど)、セッション制御文(SET ROLEなど)またはシステム制御文(ALTER SYSTEMなど)を実行できません。また、DDL文(CREATEなど)には自動コミットが続くため、これも実行できません。

ファンクション本体内の SQL 文が規則に違反すると、実行時(文が解析されるとき)にエラーが発生します。

この規則に違反していないかどうかを確認するには、RESTRICT_REFERENCESプラグマ(コンパイラ・ディレクティブ)を使用します。プラグマは、ファンクションがデータベース表またはパッケージ変数に対する読込みまたは書込みを行っていないことを示します。たとえば次のプラグマは、パッケージ・ファンクション credit_okがデータベースへの書込み禁止状態(WNDS)、およびパッケージに読込み禁止状態(RNPS)であることを示します。

PL/SQL のサブプログラムの使用 8-29

Page 286: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのパラメータのエイリアシングの理解

CREATE PACKAGE loans AS FUNCTION credit_ok RETURN BOOLEAN; PRAGMA RESTRICT_REFERENCES (credit_ok, WNDS, RNPS);END loans;/

注意注意注意注意 : 静的 INSERT文、UPDATE文または DELETE文は、常に WNDSに違反します。また、列を読み取る場合は RNDS(データベースに読込み禁止状態)にも違反します。動的INSERT文、UPDATE文または DELETE文は、常に WNDSおよび RNDSに違反します。

完全な構文については、13-150 ページの「RESTRICT_REFERENCES プラグマ」を参照してください。純正規則の詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解サブプログラムのパラメータのエイリアシングの理解サブプログラムのコールを 適化するために、PL/SQL コンパイラでは、2 つのパラメータ引渡し方式のいずれかを選択できます。値方式では、実パラメータの値がサブプログラムに渡されます。参照方式では、値へのポインタのみが渡されます。この場合、実パラメータと仮パラメータとは同じ項目を参照します。

NOCOPYコンパイラ・ヒントによって、エイリアシングの可能性が高くなります(つまり、異なる 2 つの名前が同じメモリー位置を参照するようになります)。これは、グローバル変数がサブプログラムのコールの中で実パラメータとして使用され、そのサブプログラム内で参照されると発生します。結果はコンパイラが選択するパラメータの引渡し方式に依存するため、予測不能になります。

例例例例 8-7 NOCOPY ヒントを指定したグローバル変数の引渡しによるエイリアシングヒントを指定したグローバル変数の引渡しによるエイリアシングヒントを指定したグローバル変数の引渡しによるエイリアシングヒントを指定したグローバル変数の引渡しによるエイリアシング

次の例では、プロシージャ ADD_ENTRYは、VARRAY LEXICONをパラメータとグローバル変数の両方として参照しています。ADD_ENTRYがコールされると、識別子 WORD_LISTおよび LEXICONは同じ VARRAY を指定します。

DECLARE TYPE Definition IS RECORD ( word VARCHAR2(20), meaning VARCHAR2(200)); TYPE Dictionary IS VARRAY(2000) OF Definition; lexicon Dictionary := Dictionary(); PROCEDURE add_entry (word_list IN OUT NOCOPY Dictionary) IS BEGIN word_list(1).word := 'aardvark'; lexicon(1).word := 'aardwolf'; END;BEGIN lexicon.EXTEND; add_entry(lexicon);

8-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 287: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのパラメータのエイリアシングの理解

dbms_output.put_line(lexicon(1).word);END;/

コンパイラが NOCOPYヒントに従う場合、プログラムは aardwolfを出力します。WORD_LISTへの代入はポインタを通じてただちに実行され、LEXICONへの代入によって上書きされます。

NOCOPYヒントが省略された場合またはコンパイラが NOCOPYヒントに従わない場合、プログラムは aardvarkを出力します。WORD_LISTへの代入には VARRAY の内部コピーが使用されます。これは、プロシージャの終了時に実パラメータにコピーされます(LEXICONの内容を上書きします)。

例例例例 8-8 同じパラメータの複数回の引渡しによるエイリアシング同じパラメータの複数回の引渡しによるエイリアシング同じパラメータの複数回の引渡しによるエイリアシング同じパラメータの複数回の引渡しによるエイリアシング

エイリアシングは、1 回のサブプログラム・コールに、同じ実パラメータが 2 回以上現れる場合にも発生します。次の例では、n2が IN OUTのパラメータであるため、実パラメータの値は、プロシージャが終了するまで更新されません。そのため、 初の put_lineは 10(nの初期値)を出力し、3 番目の put_lineは 20 を出力します。ただし、n3は NOCOPYパラメータであるため、実パラメータの値はただちに更新されます。2 番目の put_lineが 30を出力するのはこのためです。

DECLARE n NUMBER := 10; PROCEDURE do_something ( n1 IN NUMBER, n2 IN OUT NUMBER, n3 IN OUT NOCOPY NUMBER) IS BEGIN n2 := 20; dbms_output.put_line(n1); -- prints 10 n3 := 30; dbms_output.put_line(n1); -- prints 30 END;BEGIN do_something(n, n, n); dbms_output.put_line(n); -- prints 20END;/

PL/SQL のサブプログラムの使用 8-31

Page 288: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

サブプログラムのパラメータのエイリアシングの理解

例例例例 8-9 同じ作業領域へのカーソル変数の代入によるエイリアシング同じ作業領域へのカーソル変数の代入によるエイリアシング同じ作業領域へのカーソル変数の代入によるエイリアシング同じ作業領域へのカーソル変数の代入によるエイリアシング

カーソル変数はポインタであるため、カーソル変数にもエイリアシングの可能性があります。次の例では、代入の後、emp_cv2は emp_cv1の別名になります。これは、両者が同じ問合せ作業領域を指すためです。 初の 2 行はすでに emp_cv1からフェッチされているため、emp_cv2からの 1 番目のフェッチは、1 番目ではなく 3 番目の行をフェッチします。emp_cv1は閉じられているため、emp_cv2からの 2 番目のフェッチは失敗します。

PROCEDURE get_emp_data ( emp_cv1 IN OUT EmpCurTyp, emp_cv2 IN OUT EmpCurTyp) IS emp_rec employees%ROWTYPE;BEGIN OPEN emp_cv1 FOR SELECT * FROM employees; emp_cv2 := emp_cv1; FETCH emp_cv1 INTO emp_rec; -- fetches first row FETCH emp_cv1 INTO emp_rec; -- fetches second row FETCH emp_cv2 INTO emp_rec; -- fetches third row CLOSE emp_cv1; FETCH emp_cv2 INTO emp_rec; -- raises INVALID_CURSOREND;/

8-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 289: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL パッケージの

9

PL/SQL パッケージの使用パッケージの使用パッケージの使用パッケージの使用

この章では、互いに関連する PL/SQL コードとデータを 1 つのパッケージにまとめる方法について説明します。パッケージには、API を構成するプロシージャの集まりや、型定義と変数宣言の集まりなどが考えられます。パッケージをコンパイルしてデータベースに格納し、その内容を複数のアプリケーションで共有できます。

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

� PL/SQL パッケージ(9-2 ページ)

� PL/SQL パッケージのメリット(9-4 ページ)

� パッケージ仕様部の理解(9-5 ページ)

� パッケージ本体の理解(9-7 ページ)

� パッケージ機能の例(9-8 ページ)

� パッケージのプライベート項目とパブリック項目(9-13 ページ)

� パッケージ・サブプログラムのオーバーロード(9-13 ページ)

� パッケージ STANDARD による PL/SQL 環境の定義(9-14 ページ)

� 製品固有のパッケージの概要(9-15 ページ)

� パッケージ作成のガイドライン(9-17 ページ)

� パッケージでのカーソル仕様部と本体の分離(9-17 ページ)

使用 9-1

Page 290: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL パッケージ

PL/SQL パッケージパッケージパッケージパッケージパッケージパッケージパッケージパッケージとは、論理的に関連する PL/SQL の型、変数およびサブプログラムをグループ化したスキーマ・オブジェクトのことです。通常、パッケージは仕様部と本体の 2 つの部分で構成されますが、本体が不要な場合もあります。仕様部仕様部仕様部仕様部はパッケージへのインタフェースです。ここでは、型、変数、定数、例外、カーソル、およびパッケージの外から参照できるサブプログラムを宣言します。本体本体本体本体は、カーソルの問合せとサブプログラムのコードを定義します。

仕様部はインタフェース、本体はブラック・ボックスと考えることができます。パッケージの仕様部を変更しなくても、本体をデバッグ、拡張または置換できます。

パッケージ仕様部を作成するには、SQL の CREATE PACKAGE文を使用します。必要に応じて、CREATE PACKAGE BODY文でパッケージ本体を定義します。

仕様部には、ストアド・プロシージャやその他のパッケージ外部のコードから見えるパブパブパブパブリックな宣言リックな宣言リックな宣言リックな宣言を入れます。サブプログラムは、仕様部で他のすべての項目の後で 後に宣言する必要があります(ただし、特定のファンクションの名前を指定するプラグマは、ファンクション仕様部の後に宣言する必要があります)。

本体には、実装の細部と、パッケージ外部のコードからは隠されているプライベートな宣言プライベートな宣言プライベートな宣言プライベートな宣言を入れます。パッケージ本体の宣言部の後には、オプションの初期化部があります。ここには、パッケージ変数を初期化する文と、その他の一度のみの設定を行う文を入れます。

AUTHID句は、すべてのパッケージ・サブプログラムがその定義者(デフォルト)と実行者のどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が定義者と実行者のどちらのスキーマで解決されるかを決定します。詳細は、8-20 ページの「実行者権限と定義者権限の使用(AUTHID 句)」を参照してください。

コール仕様コール仕様コール仕様コール仕様を使用すると、パッケージ・サブプログラムを Java メソッドまたは外部 C ファンクションにマップできます。コール仕様は、Java または C 言語の名前、パラメータ型および戻り型を対応する SQL にマップします。Java コール仕様を作成する方法は、『Oracle Database Java 開発者ガイド』を参照してください。C コール仕様を作成する方法は、

『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

PL/SQL パッケージの内容パッケージの内容パッケージの内容パッケージの内容� パッケージ変数の get メソッドと set メソッド。これらは他のプロシージャからの直接読

取りや書込みを避ける場合に使用します。

� SQL 問合せテキストのあるカーソル宣言。同じ問合せテキストを複数の場所で再利用する方が、同じ問合せを少しずつ変更して毎回再入力するより効率的です。また、多くの場所で使用されている問合せを変更する必要がある場合、メンテナンスも容易になります。

� 例外の宣言。これらの宣言は、通常、コールされたサブプログラム内で例外を処理するために、様々なプロシージャから参照できる必要があります。

9-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 291: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL パッケージ

� 相互にコールするプロシージャとファンクションの宣言。パッケージ化されたプロシージャやファンクションのコンパイルの順序にとらわれる必要はありません。このため、スタンドアロン・ストアド・プロシージャとファンクションが互いにコールし合う場合よりも便利です。

� オーバーロードされたプロシージャとファンクションの宣言。名前は同じだが異なるパラメータ・セットを使用する、複数のバリエーションのプロシージャまたはファンクションを作成できます。

� 同じセッション内のプロシージャ・コール間で使用可能な状態に保つ変数。パッケージ内でグローバル変数のように扱うことができます。

� PL/SQL コレクション型の型宣言。ストアド・プロシージャまたはファンクション間でコレクションをパラメータとして渡すには、コール元とコール先のサブプログラムの両方でコレクションを参照できるように、パッケージ内で型を宣言する必要があります。

PL/SQL パッケージの例パッケージの例パッケージの例パッケージの例次の例では、1 つのレコード型とカーソルと 2 つの人事プロシージャをパッケージ化しています。hire_employeeプロシージャでは、順序 empno_seqと SYSDATEファンクションを使用して、新しい従業員番号と入社日を挿入しています。

CREATE OR REPLACE PACKAGE emp_actions AS -- spec TYPE EmpRecTyp IS RECORD (emp_id INT, salary REAL); CURSOR desc_salary RETURN EmpRecTyp; PROCEDURE hire_employee ( ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER); PROCEDURE fire_employee (emp_id NUMBER);END emp_actions;/

CREATE OR REPLACE PACKAGE BODY emp_actions AS -- body CURSOR desc_salary RETURN EmpRecTyp IS SELECT empno, sal FROM emp ORDER BY sal DESC; PROCEDURE hire_employee ( ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER) IS BEGIN INSERT INTO emp VALUES (empno_seq.NEXTVAL, ename, job,

PL/SQL パッケージの使用 9-3

Page 292: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL パッケージのメリット

mgr, SYSDATE, sal, comm, deptno); END hire_employee;

PROCEDURE fire_employee (emp_id NUMBER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee;END emp_actions;/

アプリケーションから参照およびアクセスできるのは、パッケージ仕様部の宣言のみです。パッケージ本体の実装の詳細は隠ぺいされ、アクセスできません。そのため、コールする側のプログラムを再コンパイルしなくても、本体(実装)を変更できます。

PL/SQL パッケージのメリットパッケージのメリットパッケージのメリットパッケージのメリットソフトウェア・エンジニアリングではパッケージに長い歴史があります。大規模なシステムのチーム開発において、パッケージは信頼性のある、メンテナンスが容易で再利用可能なコードに重要な機能を提供しています。

モジュール性モジュール性モジュール性モジュール性パッケージを使用すると、論理的に関連した型、項目およびサブプログラムを、名前付きのPL/SQL モジュールにカプセル化できます。個々のパッケージは理解しやすく、パッケージ間のインタフェースは単純かつ明快で、明確に定義されています。これはアプリケーション開発に役立ちます。

アプリケーションの設計の容易さアプリケーションの設計の容易さアプリケーションの設計の容易さアプリケーションの設計の容易さ

アプリケーション設計の 初の段階では、パッケージの仕様部に含まれるインタフェース情報のみが必要です。仕様部は本体がなくてもコーディングし、コンパイルできます。仕様部のコンパイルが終了すると、そのパッケージを参照するストアド・サブプログラムもコンパイルできます。アプリケーション作成の 終段階になるまで、パッケージ本体を完全に定義する必要はありません。

情報の隠ぺい情報の隠ぺい情報の隠ぺい情報の隠ぺい

パッケージを使用すると、個々の型、項目およびサブプログラムについて、それがパブリック(可視でアクセス可能)なのか、またはプライベート(隠されていてアクセス不可)なのかを指定できます。たとえば、パッケージに含まれる 4 つのサブプログラムのうち、3 つをパブリック、1 つをプライベートにすることもできます。パッケージはプライベートなサブプログラムの実装を隠ぺいするため、実装が変更された場合も(アプリケーションではなく)パッケージのみが影響を受けます。このため、メンテナンスや機能拡張が簡単に実施できます。また、実装上の細部をユーザーから隠ぺいすることで、パッケージの整合性を維持できます。

9-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 293: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ仕様部の理解

機能の追加機能の追加機能の追加機能の追加

パッケージ化されたパブリック変数およびカーソルは、セッションを通じて存続します。このため、同じ環境の中で実行するすべてのサブプログラムで共有できます。これによって、データベースに格納することなくトランザクション間でデータをメンテナンスできます。

高いパフォーマンス高いパフォーマンス高いパフォーマンス高いパフォーマンス

パッケージ・サブプログラムを初めてコールすると、パッケージ全体がメモリーにロードされます。パッケージ内の関連するサブプログラムに対する 2 度目以降のコールでは、ディスク I/O は必要ありません。

パッケージ化すると互いに依存することがなくなるため、不要な再コンパイルを避けることができます。たとえば、パッケージ・ファンクションの本体を変更した場合、Oracle はそのファンクションをコールする他のサブプログラムを再コンパイルしません。これらのサブプログラムは仕様部で宣言されたパラメータと戻り値にのみ依存するためです。再コンパイルする必要があるのは、仕様部が変更されたときのみです。

パッケージ仕様部の理解パッケージ仕様部の理解パッケージ仕様部の理解パッケージ仕様部の理解パッケージ仕様部にはパブリック宣言が入っています。宣言された項目は、パッケージ内のどの場所からでも、同じスキーマ内の別のサブプログラムからでもアクセス可能です。図9-1 に有効範囲を示します。

図図図図 9-1 パッケージの有効範囲パッケージの有効範囲パッケージの有効範囲パッケージの有効範囲

仕様部には、アプリケーションが利用できるパッケージ・リソースのリストがあります。アプリケーションがリソースを使用するために必要な情報は、すべて仕様部の中にあります。たとえば、次の宣言は、facという名前のファンクションが INTEGER型の引数を 1 つ取り、INTEGER型の値を戻すことを示しています。

FUNCTION fac (n INTEGER) RETURN INTEGER; -- returns n!

PL/SQL パッケージの使用 9-5

Page 294: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ仕様部の理解

ファンクションのコールに必要な情報はこれのみです。ユーザーは fac の下位の実装のこと(それが反復を利用しているのか、再帰を利用しているのかなど)を考える必要がありません。

仕様部で宣言されているのが型、定数、変数、例外およびコール仕様部のみであれば、パッケージ本体は不要です。下位の実装を持つのは、サブプログラムとカーソルのみです。次の例では、パッケージは型、例外および変数を宣言していますが、サブプログラムまたはカーソルを持たないため、パッケージ本体は不要です。このようなパッケージを使用すると、セッションを通じて存続するグローバル変数(ストアド・プロシージャ、ファンクションおよびトリガーで使用できる)を定義できます。

CREATE PACKAGE trans_data AS -- bodiless package TYPE TimeRec IS RECORD ( minutes SMALLINT, hours SMALLINT); TYPE TransRec IS RECORD ( category VARCHAR2, account INT, amount REAL, time_of TimeRec); minimum_balance CONSTANT REAL := 10.00; number_processed INT; insufficient_funds EXCEPTION;END trans_data;/

パッケージの内容の参照パッケージの内容の参照パッケージの内容の参照パッケージの内容の参照パッケージの仕様部で宣言された型、項目、サブプログラムおよびコール仕様部を参照するときには、次のようにドット表記法を使用します。

package_name.type_namepackage_name.item_namepackage_name.subprogram_namepackage_name.call_spec_name

パッケージ内容は、データベース・トリガー、ストアド・サブプログラム、3GL アプリケーション・プログラムおよび様々な Oracle のツール製品から参照できます。たとえば、パッケージ・プロシージャ hire_employeeは次のように SQL*Plus からコールします。

CALL emp_actions.hire_employee('TATE', 'CLERK', ...);

9-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 295: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ本体の理解

次の例では、Pro*C プログラムの無名ブロックから同じプロシージャをコールしています。実パラメータ emp_nameと job_titleはホスト変数です。

EXEC SQL EXECUTE BEGIN emp_actions.hire_employee(:emp_name, :job_title, ...);

制限制限制限制限リモート・パッケージ変数は、直接的にも間接的にも参照できません。たとえば、プロシージャがパッケージ変数を参照する場合、データベース・リンクを通じてプロシージャをコールすることはできません。

また、パッケージ内ではホスト変数を参照できません。

パッケージ本体の理解パッケージ本体の理解パッケージ本体の理解パッケージ本体の理解パッケージ本体には、パッケージ仕様部で宣言されているすべてのカーソルとサブプログラムの実装が含まれています。パッケージ本体で定義されたサブプログラムにパッケージの外側からアクセスするには、その指定がパッケージ仕様部に存在している必要があります。サブプログラムの仕様部がパッケージ仕様部に含まれていない場合、サブプログラムは同じパッケージ内の他のサブプログラムからのみコールできます。

サブプログラムの仕様部と本体を一致させるために、PL/SQL は、それらのヘッダーをトークンごとに比較します。このため、空白を除いて、ヘッダーは一語一語が一致している必要があります。一致していない場合、PL/SQL は例外を呼び出します。次に例を示します。

CREATE PACKAGE emp_actions AS ... PROCEDURE calc_bonus (date_hired emp.hiredate%TYPE, ...);END emp_actions;/

CREATE PACKAGE BODY emp_actions AS ... PROCEDURE calc_bonus (date_hired DATE, ...) IS -- parameter declaration raises an exception because 'DATE' -- does not match 'emp.hiredate%TYPE' word for word BEGIN ... END;END emp_actions;/

パッケージ本体には、パッケージの内部動作に必要な型や項目を定義するプライベート宣言を入れることもできます。これらの宣言の有効範囲は、パッケージ本体に対してローカルです。このため、宣言された型と項目はパッケージ本体の中からでなければアクセスできません。パッケージ仕様部とは異なり、パッケージ本体の宣言部にはサブプログラムの本体を置くことができます。

PL/SQL パッケージの使用 9-7

Page 296: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ機能の例

パッケージ本体の宣言部の後には、オプションの初期化部があります。ここには、一般にパッケージの中で宣言済の変数を初期化する文がいくつか置かれています。

サブプログラムとは異なり、パッケージをコールすることもパッケージにパラメータを渡すこともできないため、パッケージの初期化部にはあまり意味がありません。このため、パッケージの初期化部は、パッケージが初めて参照されたときに一度のみ実行されます。

すでに説明したように、仕様部で宣言されているのが型、定数、変数、例外およびコール仕様部のみであればパッケージ本体は不要です。ただしその場合でも、パッケージ本体を使用して、パッケージ仕様部で宣言した項目を初期化できます。

パッケージ機能の例パッケージ機能の例パッケージ機能の例パッケージ機能の例次に示す emp_actionsという名前のパッケージの例を考えます。パッケージ仕様部では、次のような型、項目およびサブプログラムを宣言します。

� EmpRecTyp型および DeptRecTyp型

� カーソル desc_salary

� 例外 invalid_salary

� ファンクション hire_employeeおよび nth_highest_salary

� プロシージャ fire_employeeおよび raise_salary

パッケージを作成すると、そのパッケージの型の参照、サブプログラムのコール、カーソルの使用、例外のコールなどを行うアプリケーションを開発できます。パッケージを作成すると、そのパッケージは Oracle データベースに格納され、そのパッケージの実行権限を持つアプリケーションから使用されます。

CREATE PACKAGE emp_actions AS /* Declare externally visible types, cursor, exception. */ TYPE EmpRecTyp IS RECORD (emp_id INT, salary REAL); TYPE DeptRecTyp IS RECORD (dept_id INT, location VARCHAR2); CURSOR desc_salary RETURN EmpRecTyp; invalid_salary EXCEPTION;

/* Declare externally callable subprograms. */ FUNCTION hire_employee ( ename VARCHAR2, job VARCHAR2, mgr REAL, sal REAL, comm REAL, deptno REAL) RETURN INT; PROCEDURE fire_employee (emp_id INT); PROCEDURE raise_salary (emp_id INT, grade INT, amount REAL); FUNCTION nth_highest_salary (n INT) RETURN EmpRecTyp;

9-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 297: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ機能の例

END emp_actions;/

CREATE PACKAGE BODY emp_actions AS number_hired INT; -- visible only in this package

/* Fully define cursor specified in package. */ CURSOR desc_salary RETURN EmpRecTyp IS SELECT empno, sal FROM emp ORDER BY sal DESC;

/* Fully define subprograms specified in package. */ FUNCTION hire_employee ( ename VARCHAR2, job VARCHAR2, mgr REAL, sal REAL, comm REAL, deptno REAL) RETURN INT IS new_empno INT; BEGIN SELECT empno_seq.NEXTVAL INTO new_empno FROM dual; INSERT INTO emp VALUES (new_empno, ename, job, mgr, SYSDATE, sal, comm, deptno); number_hired := number_hired + 1; RETURN new_empno; END hire_employee;

PROCEDURE fire_employee (emp_id INT) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee;

/* Define local function, available only inside package. */ FUNCTION sal_ok (rank INT, salary REAL) RETURN BOOLEAN IS min_sal REAL; max_sal REAL; BEGIN SELECT losal, hisal INTO min_sal, max_sal FROM salgrade WHERE grade = rank; RETURN (salary >= min_sal) AND (salary <= max_sal); END sal_ok;

PROCEDURE raise_salary (emp_id INT, grade INT, amount REAL) IS salary REAL; BEGIN SELECT sal INTO salary FROM emp WHERE empno = emp_id; IF sal_ok(grade, salary + amount) THEN

PL/SQL パッケージの使用 9-9

Page 298: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ機能の例

UPDATE emp SET sal = sal + amount WHERE empno = emp_id; ELSE RAISE invalid_salary; END IF; END raise_salary;

FUNCTION nth_highest_salary (n INT) RETURN EmpRecTyp IS emp_rec EmpRecTyp; BEGIN OPEN desc_salary; FOR i IN 1..n LOOP FETCH desc_salary INTO emp_rec; END LOOP; CLOSE desc_salary; RETURN emp_rec; END nth_highest_salary;

BEGIN -- initialization part starts here INSERT INTO emp_audit VALUES (SYSDATE, USER, 'EMP_ACTIONS'); number_hired := 0;END emp_actions;/

パッケージの初期化部は、パッケージが初めて参照されたときに一度のみ実行されることに注意してください。このため、上の例の INSERT 文では、データベース表 emp_auditに挿入される行は 1 行のみです。また、変数 number_hiredは一度しか初期化されません。

プロシージャ hire_employeeがコールされるたびに、変数 number_hiredが更新されます。ただし、number_hiredが保持しているカウントは各セッションによって異なります。つまり、カウントは全ユーザーが処理した数ではなく、1 人のユーザーが処理した新しい従業員の数を反映します。

次の例は、一般的な銀行トランザクションを処理するパッケージです。営業時間の終了後も、現金自動預払い機で出金および入金のトランザクションが入力され、翌朝になってから口座に適用されると仮定します。

CREATE PACKAGE bank_transactions AS /* Declare externally visible constant. */ minimum_balance CONSTANT REAL := 100.00; /* Declare externally callable procedures. */ PROCEDURE apply_transactions; PROCEDURE enter_transaction ( acct INT, kind CHAR, amount REAL);END bank_transactions;/

9-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 299: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ機能の例

CREATE PACKAGE BODY bank_transactions AS /* Declare global variable to hold transaction status. */ new_status VARCHAR2(70) := 'Unknown';

/* Use forward declarations because apply_transactions calls credit_account and debit_account, which are not yet declared when the calls are made. */ PROCEDURE credit_account (acct INT, credit REAL); PROCEDURE debit_account (acct INT, debit REAL);

/* Fully define procedures specified in package. */ PROCEDURE apply_transactions IS /* Apply pending transactions in transactions table to accounts table. Use cursor to fetch rows. */ CURSOR trans_cursor IS SELECT acct_id, kind, amount FROM transactions WHERE status = 'Pending' ORDER BY time_tag FOR UPDATE OF status; -- to lock rows BEGIN FOR trans IN trans_cursor LOOP IF trans.kind = 'D' THEN debit_account(trans.acct_id, trans.amount); ELSIF trans.kind = 'C' THEN credit_account(trans.acct_id, trans.amount); ELSE new_status := 'Rejected'; END IF; UPDATE transactions SET status = new_status WHERE CURRENT OF trans_cursor; END LOOP; END apply_transactions;

PROCEDURE enter_transaction ( /* Add a transaction to transactions table. */ acct INT, kind CHAR, amount REAL) IS BEGIN INSERT INTO transactions VALUES (acct, kind, amount, 'Pending', SYSDATE); END enter_transaction;

/* Define local procedures, available only in package. */ PROCEDURE do_journal_entry ( /* Record transaction in journal. */ acct INT,

PL/SQL パッケージの使用 9-11

Page 300: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ機能の例

kind CHAR, new_bal REAL) IS BEGIN INSERT INTO journal VALUES (acct, kind, new_bal, sysdate); IF kind = 'D' THEN new_status := 'Debit applied'; ELSE new_status := 'Credit applied'; END IF; END do_journal_entry;

PROCEDURE credit_account (acct INT, credit REAL) IS /* Credit account unless account number is bad. */ old_balance REAL; new_balance REAL; BEGIN SELECT balance INTO old_balance FROM accounts WHERE acct_id = acct FOR UPDATE OF balance; -- to lock the row new_balance := old_balance + credit; UPDATE accounts SET balance = new_balance WHERE acct_id = acct; do_journal_entry(acct, 'C', new_balance); EXCEPTION WHEN NO_DATA_FOUND THEN new_status := 'Bad account number'; WHEN OTHERS THEN new_status := SUBSTR(SQLERRM,1,70); END credit_account;

PROCEDURE debit_account (acct INT, debit REAL) IS /* Debit account unless account number is bad or account has insufficient funds. */ old_balance REAL; new_balance REAL; insufficient_funds EXCEPTION; BEGIN SELECT balance INTO old_balance FROM accounts WHERE acct_id = acct FOR UPDATE OF balance; -- to lock the row new_balance := old_balance - debit; IF new_balance >= minimum_balance THEN UPDATE accounts SET balance = new_balance WHERE acct_id = acct; do_journal_entry(acct, 'D', new_balance); ELSE

9-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 301: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ・サブプログラムのオーバーロード

RAISE insufficient_funds; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN new_status := 'Bad account number'; WHEN insufficient_funds THEN new_status := 'Insufficient funds'; WHEN OTHERS THEN new_status := SUBSTR(SQLERRM,1,70); END debit_account;END bank_transactions;/

このパッケージでは初期化部を使用していません。

パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目パッケージのプライベート項目とパブリック項目パッケージ emp_actionsのパッケージ本体では、0(ゼロ)に初期化される変数number_hiredが宣言されています。本体で宣言される項目は、パッケージ内でしか使用できません。このため、パッケージの外側の PL/SQL コードからは変数 number_hiredを参照できません。このような項目はプライベートプライベートプライベートプライベートと呼ばれます。

例外 invalid_salaryなど、emp_actionsの仕様部で宣言された項目は、パッケージの外からも見えます。このため、例外 invalid_salaryはどの PL/SQL コードからも参照できます。このような項目はパブリックパブリックパブリックパブリックと呼ばれます。

セッションを通じて、または複数のトランザクションの間で維持する必要がある項目は、パッケージ本体の宣言部に置くようにしてください。たとえば、number_hiredの値はhire_employeeへの複数のコールの間も保持されています。セッションが終了すると、値が失われます。

パブリックにする必要がある項目は、パッケージ仕様部の中に置いてください。たとえば、bank_transactionsのパッケージ仕様部で宣言された定数 minimum_balanceは、パブリックで使用可能です。

パッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロードパッケージ・サブプログラムのオーバーロードPL/SQL では、パッケージ化された複数のサブプログラムに同じ名前を付けることができます。サブプログラムで、データ型が異なるパラメータからなる類似したパラメータのセットを受け取れるようにする場合は、この方法が便利です。たとえば、次のパッケージではjournalizeという名前の 2 つのプロシージャを定義しています。

CREATE PACKAGE journal_entries AS ... PROCEDURE journalize (amount REAL, trans_date VARCHAR2); PROCEDURE journalize (amount REAL, trans_date INT);

PL/SQL パッケージの使用 9-13

Page 302: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ STANDARD による PL/SQL 環境の定義

END journal_entries;/

CREATE PACKAGE BODY journal_entries AS ... PROCEDURE journalize (amount REAL, trans_date VARCHAR2) IS BEGIN INSERT INTO journal VALUES (amount, TO_DATE(trans_date, 'DD-MON-YYYY')); END journalize;

PROCEDURE journalize (amount REAL, trans_date INT) IS BEGIN INSERT INTO journal VALUES (amount, TO_DATE(trans_date, 'J')); END journalize;END journal_entries;/

1 番目のプロシージャは trans_dateを文字列として受け取りますが、2 番目のプロシージャは数値(ユリウス日付)として受け取ります。ただし、どちらのプロシージャもデータを適切に処理します。オーバーロードされたサブプログラムに適用される規則については、8-12 ページの「サブプログラム名のオーバーロード」を参照してください。

パッケージパッケージパッケージパッケージ STANDARD によるによるによるによる PL/SQL 環境の定義環境の定義環境の定義環境の定義STANDARDという名前のパッケージでは PL/SQL 環境を定義しています。このパッケージの仕様部では、型、例外およびサブプログラムをグローバルに宣言します。それらは、自動的に PL/SQL プログラムで使用可能になります。たとえば、パッケージ STANDARDでは、引数の絶対値を戻すファンクション ABSを次のように宣言します。

FUNCTION ABS (n NUMBER) RETURN NUMBER;

パッケージ STANDARDの内容は、アプリケーションから直接見ることができます。その内容を参照する場合もパッケージ名に接頭辞を付けて修飾名にする必要はありません。たとえば、ABSはデータベース・トリガー、ストアド・サブプログラム、Oracle のツール製品または 3GL アプリケーションから次のようにコールできます。

abs_diff := ABS(x - y);

ユーザー独自の ABSを宣言すると、ローカル宣言がグローバル宣言をオーバーライドします。ただし、次に示すように、完全な名前を指定して、組込みファンクションをコールできます。

abs_diff := STANDARD.ABS(x - y);

9-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 303: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

製品固有のパッケージの概要

ほとんどの組込みファンクションはオーバーロードされています。たとえば、パッケージSTANDARDには次のような宣言があります。

FUNCTION TO_CHAR (right DATE) RETURN VARCHAR2;FUNCTION TO_CHAR (left NUMBER) RETURN VARCHAR2;FUNCTION TO_CHAR (left DATE, right VARCHAR2) RETURN VARCHAR2;FUNCTION TO_CHAR (left NUMBER, right VARCHAR2) RETURN VARCHAR2;

PL/SQL は、仮パラメータと実パラメータの数とデータ型を比較して、どの TO_CHARのコールかを判定します。

製品固有のパッケージの概要製品固有のパッケージの概要製品固有のパッケージの概要製品固有のパッケージの概要Oracle といくつかの Oracle のツール製品では、PL/SQL、SQL、Java またはその他のプログラミング環境からコールできる API を定義した製品固有のパッケージを用意しています。広く使用されているパッケージのうち、いくつかを次に示します。詳細は、『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

DBMS_ALERT パッケージパッケージパッケージパッケージDBMS_ALERTパッケージでは、データベース内の特定の値が変更されたときに、データベース・トリガーを使用してアプリケーションに警告できます。その警告は、トランザクション・ベースで、非同期です(つまり、警告はタイミング・メカニズムとは無関係に作動します)。たとえば、会社ではこのパッケージを使用して、株や債券の取り引き価格が更新されたときに、投資ポートフォリオの値を更新できます。

DBMS_OUTPUT パッケージパッケージパッケージパッケージDBMS_OUTPUTパッケージを使用すると、PL/SQL ブロックとサブプログラムからの出力を表示できます。これによって、テストとデバッグが簡単になります。put_lineプロシージャは、情報を SGA のバッファに出力します。この情報は、プロシージャ get_lineをコールするか、SQL*Plus に SERVEROUTPUTONを設定することによって表示します。たとえば、次のストアド・プロシージャを作成するとします。

CREATE OR REPLACE PROCEDURE list_tables ASBEGIN dbms_output.put_line('These are the tables you own:'); FOR item IN (SELECT table_name FROM user_tables) LOOP dbms_output.put_line(item.table_name); END LOOP;END;/

PL/SQL パッケージの使用 9-15

Page 304: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

製品固有のパッケージの概要

次のコマンドを発行すると、SQL*Plus はプロシージャからの出力を表示します。

SQL> SET SERVEROUTPUT ONSQL> EXEC list_tables;

出力が長い場合は、SET SERVEROUTPUT ON SIZE 1000000を発行して、より大きな出力バッファを使用する必要があります。

DBMS_PIPE パッケージパッケージパッケージパッケージパッケージ DBMS_PIPEを使用すると、名前付きパイプを介して異なるセッション間で通信できます。(パイプとは、あるプロセスから他のプロセスに情報を渡すために使用するメモリーの領域のことです。)pack_messageプロシージャと send_messageプロシージャを使用してパイプの中にメッセージをパックし、同じインスタンス内の別のセッションまたは待機中のアプリケーション(UNIX プログラムなど)に送信できます。

パイプのもう一端では、receive_messageプロシージャと unpack_messageプロシージャを使用して、メッセージを受信し、アンパック(読取り)できます。名前付きパイプは、あらゆる点で便利です。たとえば、データを収集する C プログラムを作成し、次にそれをパイプを介して Oracle データベース内のストアド・プロシージャに送信できます。

UTL_FILE パッケージパッケージパッケージパッケージパッケージ UTL_FILEを使用すると、PL/SQL プログラムでオペレーティング・システム

(OS)のテキスト・ファイルを読み書きできます。このパッケージは、OS の標準ストリーム・ファイル I/O の制限されたバージョン(OPEN、PUT、GET、CLOSE の操作を含む)を提供します。

テキスト・ファイルの読み書きを実行する場合は、ファンクション fopenをコールします。このファンクションは、それ以降のプロシージャ・コールで使用するためのファイル・ハンドルを戻します。たとえば、プロシージャ put_lineは、テキスト文字列と行終了文字をオープン・ファイルに書き込みます。また、プロシージャ get_lineは、オープン・ファイルから出力バッファにテキストの行を読み込みます。

UTL_HTTP パッケージパッケージパッケージパッケージUTL_HTTPパッケージを使用すると、PL/SQL プログラムで HTTP(Hypertext Transfer Protocol)のコールアウトを実行できます。これによって、データをインターネットから取り出すことも、Oracle Web Server カートリッジをコールすることもできます。このパッケージには 2 つのエントリ・ポイントがあり、各ポイントで URL(Uniform Resource Locator)を受け取り、指定されたサイトに接続し、要求されたデータを戻します。通常このデータは HTML(Hypertext Markup Language)形式のものです。

9-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 305: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージでのカーソル仕様部と本体の分離

パッケージ作成のガイドラインパッケージ作成のガイドラインパッケージ作成のガイドラインパッケージ作成のガイドラインパッケージを作成する場合は、別のアプリケーションで再利用できるように、汎用性を持たせるようにしてください。オラクル社が提供するパッケージをよく理解して、すでに Oracleが提供している機能と重複する機能を持つパッケージを作成しないように注意してください。

パッケージ本体の前にパッケージ仕様部を設計および定義してください。仕様部に入れるのは、コール元プログラムから見える必要のあるもののみにします。こうすることで、他の開発者が実装の細部に不適切に依存しないようにできます。

コードの変更時に必要な再コンパイルを削減するために、パッケージ仕様部に置く項目はできるかぎり少なくしておきます。そうすれば、パッケージ本体を変更しても、コール元のプロシージャを再コンパイルする必要はありません。ただし、パッケージ仕様部を変更すると、Oracle はそのパッケージを参照するすべてのストアド・サブプログラムを再コンパイルする必要があります。

パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離パッケージでのカーソル仕様部と本体の分離パッケージの中で、カーソルの仕様部を本体と切り離して別の位置に配置できます。これによって、カーソルの仕様部を変更せずに、本体のみを変更できます。パッケージの仕様部の中でカーソルの仕様部をコーディングする場合は、この構文を使用します。

CURSOR cursor_name [(parameter[, parameter]...)] RETURN return_type;

次に示す例では、%ROWTYPE属性を使用して、データベース表 empの中の行を表すレコード型を指定しています。

CREATE PACKAGE emp_stuff AS CURSOR c1 RETURN emp%ROWTYPE; -- declare cursor spec ...END emp_stuff;/

CREATE PACKAGE BODY emp_stuff AS CURSOR c1 RETURN emp%ROWTYPE IS SELECT * FROM emp WHERE sal > 2500; -- define cursor body ...END emp_stuff;/

戻り値のデータ型を RETURN句で指定しているため、カーソル仕様部には SELECT文がありません。ただしカーソル本体には、SELECT文と、カーソル仕様部と同じ RETURN句が必要です。また、SELECTリスト中の項目の数とデータ型は、RETURN句と一致する必要があります。

PL/SQL パッケージの使用 9-17

Page 306: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージでのカーソル仕様部と本体の分離

パッケージ・カーソルを使用すると柔軟性が向上します。たとえば、上の例では、カーソル仕様部を変更することなく、カーソル本体を変更できます。

次の例に示すように、PL/SQL ブロックまたはサブプログラムからパッケージ・カーソルを参照するドット表記法を使用します。

DECLARE emp_rec employees%ROWTYPE;BEGIN OPEN emp_stuff.c1; LOOP FETCH emp_stuff.c1 INTO emp_rec; /* Do more processing here... */ EXIT WHEN emp_suff.c1%NOTFOUND; END LOOP; CLOSE emp_stuff.c1;END;/

パッケージ・カーソルの有効範囲は PL/SQL ブロックに制限されません。したがって、パッケージ・カーソルをオープンすると、クローズするか、セッションから切断するまでオープンしたままになります。

9-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 307: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL エラ

10

PL/SQL エラーの処理エラーの処理エラーの処理エラーの処理

ランタイム・エラーは、設計の失敗、コーディングの間違い、ハードウェアの障害など、多くの原因で発生します。発生する可能性があるエラーをすべては予想できませんが、ユーザーの PL/SQL プログラムにとって重大なエラーに対しては、処理を準備しておくことはできます。

プログラミング言語では、通常、エラー・チェックを無効にしていないかぎり、スタック・オーバーフローや 0(ゼロ)による除算のようなランタイム・エラーが発生すると、正常な処理が停止され、オペレーティング・システムに制御が戻ります。PL/SQL には「例外処理」というメカニズムがあり、エラーが発生しても処理を続けられるように、プログラムを保護しています。

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

� PL/SQL のランタイム・エラー処理の概要(10-2 ページ)

� PL/SQL 例外のメリット(10-4 ページ)

� 事前定義の PL/SQL 例外のまとめ(10-5 ページ)

� 独自の PL/SQL 例外の定義(10-8 ページ)

� PL/SQL 例外の呼出し(10-12 ページ)

� PL/SQL 例外の伝播(10-13 ページ)

� PL/SQL 例外の再呼出し(10-16 ページ)

� 呼び出された PL/SQL 例外の処理(10-17 ページ)

� PL/SQL エラーの処理のヒント(10-20 ページ)

� PL/SQL のコンパイル時の警告の概要(10-23 ページ)

ーの処理 10-1

Page 308: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のランタイム・エラー処理の概要

PL/SQL のランタイム・エラー処理の概要のランタイム・エラー処理の概要のランタイム・エラー処理の概要のランタイム・エラー処理の概要PL/SQL では、エラー条件を例外と呼びます。例外には、(実行時システムによって)内部的に定義された例外と、ユーザーが定義した例外があります。一般的な内部例外の中には、

「0(ゼロ)による除算」や「メモリー不足」などがあります。内部的に定義された例外には、ZERO_DIVIDEや STORAGE_ERRORといった事前定義の名前を持つものもあります。それ以外の内部例外にも名前を付けることができます。

PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で、ユーザー独自の例外を定義できます。たとえば、残高がマイナスになっている銀行口座にフラグを付けるために、insufficient_fundsという名前の例外を定義できます。内部例外とは異なり、ユーザー定義の例外には名前を付ける必要があります。

エラーが発生すると例外が呼び出されます。つまり、通常の実行は中止され、PL/SQL ブロックまたはサブプログラムの例外処理部に制御が移ります。内部例外は実行時システムによって暗黙的(自動的)に呼び出されます。ユーザー定義の例外は RAISE文によって明示的に呼び出す必要があります(RAISE 文も事前定義の例外を呼び出します)。

呼び出された例外を処理するには、例外ハンドラと呼ばれる独立したルーチンを作成します。例外ハンドラが実行されると、現在のブロックの実行を中止し、外側のブロックの次の文から再開します。外側にブロックがない場合は、制御はホスト環境に戻ります。

次の例では、企業の株価収益率を計算しています。企業の収益が 0(ゼロ)の場合に除算演算を実行すると、事前定義の例外 ZERO_DIVIDEが呼び出され、ブロックの実行が中断し、制御が例外ハンドラに移ります。ブロックで特に名前を指定していないすべての例外は、オプションの OTHERSハンドラで処理します。

SET SERVEROUTPUT ON;

DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER;BEGIN-- Calculation might cause division-by-zero error. pe_ratio := stock_price / net_earnings; dbms_output.put_line('Price/earnings ratio = ' || pe_ratio);

EXCEPTION -- exception handlers begin

-- Only one of the WHEN blocks is executed.

WHEN ZERO_DIVIDE THEN -- handles 'division by zero' error dbms_output.put_line('Company must have had zero earnings.'); pe_ratio := null;

WHEN OTHERS THEN -- handles all other errors dbms_output.put_line('Some other kind of error occurred.');

10-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 309: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のランタイム・エラー処理の概要

pe_ratio := null;

END; -- exception handlers and block end here/

上の例は例外処理を示しています。詳細なエラー・チェックを行って、分母が 0(ゼロ)の場合は答えを NULL に置き換えるようにすると、例外を完全に回避できます。

DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER;BEGIN pe_ratio := case net_earnings when 0 then null else stock_price / net_earnings end;END;/

PL/SQL エラーと例外の回避および処理のガイドラインエラーと例外の回避および処理のガイドラインエラーと例外の回避および処理のガイドラインエラーと例外の回避および処理のガイドラインデータベース・プログラムには信頼性が重要であるため、エラー・チェックと例外処理の両方を使用して、プログラムがすべての可能性を処理できるようにします。

� エラー発生の可能性がある場合は常に、例外ハンドラを追加します。算術演算、文字列操作、データベース操作の間は、エラーが発生する可能性が特に高くなります。エラーはその他の場合にも発生する可能性があります。たとえば、ディスク記憶域やメモリーのハードウェア障害がコードに関係ない問題を引き起こした場合でも、コードには対処措置が必要です。

� コードが不正な入力データを受け取ることでエラー発生が予想される場合は常に、エラー・チェック・コードを追加します。コードに間違ったパラメータや NULL パラメータが渡される場合や、問合せが行を戻さない場合、または予想以上の行を戻す場合が考えられます。

� データベースが想定外の状態になった場合にもプログラムが安全に動作するようにします。たとえば、問い合せた表で列の追加や削除が行われていたり、列の型が変更されている場合があります。こうした問題を回避するには、各変数を %TYPE修飾子で宣言し、問合せ結果を保持するレコードを %ROWTYPE修飾子で宣言します。

� 例外ハンドラで WHEN OTHERS を使用するかわりに、可能なかぎり名前付き例外を処理します。事前定義の例外の名前と原因を調べておいてください。データベース操作によって特定の ORA- エラーが発生する場合は、そのエラーに名前を付けて、それを処理するハンドラを作成できるようにします。(方法についてはこの章の後半で説明します。)

PL/SQL エラーの処理 10-3

Page 310: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外のメリット

� 不正なデータの様々な組合せでコードをテストし、どのような潜在的なエラーが発生するかを調べます。

� デバッグ情報を例外ハンドラに記述します。個別の表にこのような情報を格納する場合もあります。その場合は、AUTONOMOUS_TRANSACTIONプラグマで宣言したプロシージャをコールしてください。これによって、メイン・プロシージャが行っていた処理をロールバックする場合でもデバッグ情報をコミットできます。

� 各例外ハンドラがトランザクションをコミットするか、ロールバックするか、継続するのかを慎重に考慮します。エラーがどれほど重大であっても、データベースを一貫性のある状態に保ち、不正なデータの格納を避けるようにしてください。

PL/SQL 例外のメリット例外のメリット例外のメリット例外のメリットエラー処理に例外を使用すると、次のようなメリットがあります。

例外を使用すると、1 つの例外ハンドラで多くの文の潜在的なエラーを確実に処理できます。

BEGIN SELECT ... SELECT ... procedure_that_performs_select(); ...EXCEPTION WHEN NO_DATA_FOUND THEN -- catches all 'no data found' errors

エラーが発生する可能性のある場所で逐一エラーをチェックするのではなく、単に例外ハンドラを PL/SQL ブロックに追加します。そうすると、そのブロック(またはサブブロック)で例外が呼び出されたときにその例外を確実に処理できます。

エラーの発生がすぐにはわからなかったり、不正なデータで計算を実行した場合に実行後までエラーを検出できないこともあります。この場合も、1 つの例外ハンドラで、すべての 0

(ゼロ)による除算エラー、不正な配列の添字などをトラップできます。

特定の場所でエラーをチェックする必要がある場合は、独立した例外ハンドラを持つ独立した BEGIN-END ブロックで単一の文または文のグループを囲みます。一般的なチェックを行うことも、厳密にチェックを行うこともできます。

エラー処理ルーチンを分離することで、プログラムの残りの部分がわかりやすく、理解しやすくなります。

10-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 311: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義の PL/SQL 例外のまとめ

事前定義の事前定義の事前定義の事前定義の PL/SQL 例外のまとめ例外のまとめ例外のまとめ例外のまとめPL/SQL プログラムが Oracle の規則に違反するか、そのシステムの制限を超えると、自動的に内部例外が呼び出されます。PL/SQL では、いくつかの一般的な Oracle エラーが例外として事前定義されています。たとえば、SELECT INTO文が行を戻さなかった場合は、事前定義の例外 NO_DATA_FOUNDが PL/SQL によって呼び出されます。

EXCEPTION_INITプラグマを使用して、例外名を予想される他の Oracle エラー・コードに関連付けることができます。想定外の Oracle エラーを処理するには、OTHERSハンドラを使用します。このハンドラ内では、SQLCODEファンクションと SQLERRMファンクションをコールして、Oracle エラー・コードとメッセージ・テキストを戻すことができます。エラー・コードがわかれば、EXCEPTION_INITプラグマでエラー・コードを使用して、そのエラー専用のハンドラを作成できます。

PL/SQL では、STANDARDパッケージの中で、事前定義の例外がグローバルに宣言されています。ユーザーが宣言する必要はありません。次の表に示す名前を使用すれば、事前定義の例外を処理するハンドラを作成できます。

例外例外例外例外 Oracle エラーエラーエラーエラー SQLCODE 値値値値

ACCESS_INTO_NULL ORA-06530 -6530

CASE_NOT_FOUND ORA-06592 -6592

COLLECTION_IS_NULL ORA-06531 -6531

CURSOR_ALREADY_OPEN ORA-06511 -6511

DUP_VAL_ON_INDEX ORA-00001 -1

INVALID_CURSOR ORA-01001 -1001

INVALID_NUMBER ORA-01722 -1722

LOGIN_DENIED ORA-01017 -1017

NO_DATA_FOUND ORA-01403 +100

NOT_LOGGED_ON ORA-01012 -1012

PROGRAM_ERROR ORA-06501 -6501

ROWTYPE_MISMATCH ORA-06504 -6504

SELF_IS_NULL ORA-30625 -30625

STORAGE_ERROR ORA-06500 -6500

SUBSCRIPT_BEYOND_COUNT ORA-06533 -6533

SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 -6532

PL/SQL エラーの処理 10-5

Page 312: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義の PL/SQL 例外のまとめ

次に事前定義の例外を簡単に説明します。

SYS_INVALID_ROWID ORA-01410 -1410

TIMEOUT_ON_RESOURCE ORA-00051 -51

TOO_MANY_ROWS ORA-01422 -1422

VALUE_ERROR ORA-06502 -6502

ZERO_DIVIDE ORA-01476 -1476

例外例外例外例外 呼び出される場合呼び出される場合呼び出される場合呼び出される場合

ACCESS_INTO_NULL プログラムが未初期化オブジェクトの属性に値を代入しようとしたとき。

CASE_NOT_FOUND CASE文の WHEN句で何も選択されておらず、ELSE句も

ない場合。

COLLECTION_IS_NULL プログラムが EXISTS以外のコレクション・メソッドを未

初期化のネストした表または VARRAY に適用しようとし

たか、または未初期化のネストした表または VARRAY の

要素に値を代入しようとしたとき。

CURSOR_ALREADY_OPEN すでにオープンされているカーソルをオープンしようとしたとき。カーソルをオープンするには、一度クローズする必要があります。カーソル FORループは、参照するカー

ソルを自動的にオープンします。このため、ループの内側ではカーソルをオープンできません。

DUP_VAL_ON_INDEX UNIQUE 索引によって制約されているデータベース列に、

重複した値を格納しようとしたとき。

INVALID_CURSOR オープンされていないカーソルをクローズするなど、不正なカーソル操作を実行しようとしたとき。

INVALID_NUMBER SQL 文の中で、文字列が正しい数値を表していなかった

ために、文字列から数値への変換が失敗したとき。(プロシージャ文では、VALUE_ERRORが呼び出されます。)こ

の例外は、バルク FETCH文の LIMIT句の式が正数に評価

されない場合にも呼び出されます。

LOGIN_DENIED 不正なユーザー名またはパスワードで Oracle にログオン

しようとしたとき。

例外例外例外例外 Oracle エラーエラーエラーエラー SQLCODE 値値値値

10-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 313: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

事前定義の PL/SQL 例外のまとめ

NO_DATA_FOUND SELECT INTO文が行を戻さなかったとき、ネストした表

で削除された要素を参照したとき、または索引付き表で未初期化の要素を参照したとき。

この例外は、いくつかの SQL ファンクションで終了した

ことを通知するために内部的に使用されているため、問合せの一部としてコールされるファンクション内部で呼び出された場合は、この例外が伝播されても信頼しないでください。

NOT_LOGGED_ON Oracle に接続していないプログラムが、データベース・

コールを発行した場合。

PROGRAM_ERROR PL/SQL に内部的な問題が発生した場合。

ROWTYPE_MISMATCH 1 つの代入の中に含まれるホスト・カーソル変数と

PL/SQL カーソル変数の戻り型に互換性がない場合。たと

えば、オープン・ホスト・カーソル変数をストアド・サブプログラムに渡すとき、実パラメータの戻り型と仮パラメータの戻り型には互換性が必要です。

SELF_IS_NULL プログラムが MEMBERメソッドをコールしようとしたが、

オブジェクト型のインスタンスが初期化されていなかった場合。つまり、組込みパラメータ SELFがオブジェクトを

指している場合です。このパラメータは、常に MEMBERメ

ソッドに 初に渡されるパラメータです。

STORAGE_ERROR PL/SQL のメモリーが足りない場合、またはメモリーが破

壊されている場合。

SUBSCRIPT_BEYOND_COUNT コレクション中の要素数より大きい索引番号を使用してネストした表または VARRAY の要素を参照した場合。

SUBSCRIPT_OUTSIDE_LIMIT 有効範囲外(たとえば -1)の索引番号を使用してネストし

た表または VARRAY の要素を参照した場合。

SYS_INVALID_ROWID 文字列が正しい ROWID を表していなかったために、文字

列からユニバーサル ROWID への変換が失敗した場合。

TIMEOUT_ON_RESOURCE Oracle がリソースを求めて待機しているときにタイムア

ウトが発生した場合。

TOO_MANY_ROWS SELECT INTO文が複数の行を戻した場合。

例外例外例外例外 呼び出される場合呼び出される場合呼び出される場合呼び出される場合

PL/SQL エラーの処理 10-7

Page 314: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

独自の PL/SQL 例外の定義

独自の独自の独自の独自の PL/SQL 例外の定義例外の定義例外の定義例外の定義PL/SQL ではユーザー独自の例外を定義できます。事前定義の例外とは異なり、ユーザー定義の例外は宣言する必要があり、RAISE文を使用して明示的に呼び出す必要があります。

PL/SQL 例外の宣言例外の宣言例外の宣言例外の宣言例外は PL/SQL ブロック、サブプログラムまたはパッケージの宣言部でしか宣言できません。例外は、例外の名前にキーワード EXCEPTIONを付けて宣言します。次の例では、past_dueという名前の例外を宣言しています。

DECLARE past_due EXCEPTION;

例外の宣言と変数の宣言は似ています。ただし、例外はデータ項目ではなく、エラー条件であることを覚えておいてください。変数とは異なり、例外は代入文や SQL 文では使用できません。ただし、変数と例外の有効範囲規則は同じです。

PL/SQL 例外の有効範囲規則例外の有効範囲規則例外の有効範囲規則例外の有効範囲規則同じブロックでは 1 つの例外を 2 回宣言できません。ただし、2 つの異なるブロックであれば、同じ例外を宣言できます。

ブロックの中で宣言された例外は、そのブロックに対してローカルで、そのブロックのすべてのサブブロックに対してグローバルであるとみなされます。ブロックはローカルまたはグローバルな例外しか参照できないため、サブブロックで宣言された例外を外側のブロックから参照できません。

サブブロックでグローバルな例外を再宣言すると、ローカルの宣言が優先されます。このため、サブブロックからはグローバルな例外を参照できません。ただし、グローバルな例外がラベル付きのブロックで宣言されている場合は、例外の名前をブロック・ラベルで修飾すると、グローバルな例外を参照できます。

block_label.exception_name

VALUE_ERROR 算術エラー、変換エラー、切捨てエラー、またはサイズ制約エラーが発生した場合。たとえば、列値を選択し文字変数に代入するときに、その値が変数の宣言された長さよりも長い場合、PL/SQL はその割当てを異常終了させて

VALUE_ERRORを呼び出します。プロシージャ文では、文

字列から数値への変換が失敗した場合に VALUE_ERRORが

呼び出されます。(SQL 文では、INVALID_NUMBERが呼

び出されます。)

ZERO_DIVIDE 数値を 0(ゼロ)で割ろうとしたとき。

例外例外例外例外 呼び出される場合呼び出される場合呼び出される場合呼び出される場合

10-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 315: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

独自の PL/SQL 例外の定義

次の例に有効範囲規則を示します。

DECLARE past_due EXCEPTION; acct_num NUMBER;BEGIN DECLARE ---------- sub-block begins past_due EXCEPTION; -- this declaration prevails acct_num NUMBER; due_date DATE := SYSDATE - 1; todays_date DATE := SYSDATE; BEGIN IF due_date < todays_date THEN RAISE past_due; -- this is not handled END IF; END; ------------- sub-block endsEXCEPTION WHEN past_due THEN -- does not handle RAISEd exception dbms_output.put_line('Handling PAST_DUE exception.'); WHEN OTHERS THEN dbms_output.put_line('Could not recognize PAST_DUE_EXCEPTION in this scope.');END;/

サブブロックの past_dueの宣言が優先されるため、外側のブロックは呼び出された例外を処理しません。この 2 つの例外は同じ past_dueという名前を持っていますが、同じ名前の2 つの acct_num変数が別の変数であるのと同様に、別々の例外です。したがって、RAISE文と WHEN句は別々の例外を参照しています。呼び出された例外を外側のブロックで処理するには、サブブロックから宣言を削除するか、OTHERSハンドラを定義する必要があります。

PL/SQL 例外と番号の関連付け例外と番号の関連付け例外と番号の関連付け例外と番号の関連付け : EXCEPTION_INIT プラグマプラグマプラグマプラグマ事前定義の名前がないエラー状態(通常は ORA-メッセージ)を処理するには、OTHERSハンドラまたは EXCEPTION_INITプラグマを使用する必要があります。プラグマプラグマプラグマプラグマは、実行時ではなくコンパイル時に処理されるコンパイラ・ディレクティブです。

PL/SQL では、EXCEPTION_INITプラグマでコンパイラに指示して、例外名と Oracle エラー番号を関連付けます。この関連付けによって、内部例外を名前で参照し、専用のハンドラを作成できます。エラー・スタックエラー・スタックエラー・スタックエラー・スタックまたは一連のエラー・メッセージを確認する場合、一番上のエラーがトラップおよび処理できるエラーです。

EXCEPTION_INITプラグマは、PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で、次の構文を使用して指定します。

PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);

PL/SQL エラーの処理 10-9

Page 316: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

独自の PL/SQL 例外の定義

exception_nameは事前に宣言されている例外の名前で、番号は ORA-エラー番号に対応する負の値です。次の例に示すとおり、プラグマは、同じ宣言部内の例外宣言より後に表示されます。

DECLARE deadlock_detected EXCEPTION; PRAGMA EXCEPTION_INIT(deadlock_detected, -60);BEGIN null; -- Some operation that causes an ORA-00060 errorEXCEPTION WHEN deadlock_detected THEN null; -- handle the errorEND;/

独自のエラー・メッセージの定義独自のエラー・メッセージの定義独自のエラー・メッセージの定義独自のエラー・メッセージの定義 : RAISE_APPLICATION_ERROR プロシージャプロシージャプロシージャプロシージャRAISE_APPLICATION_ERRORプロシージャを使用すると、ストアド・サブプログラムからユーザー定義の ORA-エラー・メッセージを発行できます。これを利用すると、アプリケーションに対してエラーを報告し、処理されない例外が戻されるのを回避できます。

RAISE_APPLICATION_ERRORをコールするには、次の構文を使用します。

raise_application_error(error_number, message[, {TRUE | FALSE}]);

error_numberは -20000 ~ -20999 の範囲内の負の整数で、messageは長さが 2048 バイト以内の文字列です。オプションの 3 番目のパラメータが TRUEの場合、エラーは、以前のエラーのスタックに配置されます。そのパラメータが FALSE(デフォルト)の場合、エラーは以前のエラーをすべて置換します。RAISE_APPLICATION_ERRORはパッケージDBMS_STANDARDの一部で、パッケージ STANDARDと同様に、参照する際に名前を修飾する必要はありません。

アプリケーションは、実行中のストアド・サブプログラム(またはメソッド)からのみraise_application_errorをコールできます。raise_application_errorが呼び出されると、サブプログラムは終了し、ユーザー定義のエラー番号とメッセージがアプリケーションに戻されます。エラー番号とメッセージは、Oracle エラーのようにトラップさせることができます。

次の例では、選択したエラー条件が発生した場合に(この例では、現行スキーマの所有する表の数が 1000 より少ない場合に)raise_application_errorを呼び出しています。

DECLARE num_tables NUMBER;BEGIN SELECT COUNT(*) INTO num_tables FROM USER_TABLES; IF num_tables < 1000 THEN /* Issue your own error code (ORA-20101) with your own error message. */

10-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 317: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

独自の PL/SQL 例外の定義

raise_application_error(-20101, 'Expecting at least 1000 tables'); ELSE NULL; -- Do the rest of the processing (for the non-error case). END IF;END;/

呼出し側のアプリケーションは、PL/SQL 例外を受け取り、エラー・レポート・ファンクション SQLCODEおよび SQLERRMを使用して OTHERSハンドラで処理できます。また、EXCEPTION_INITプラグマを使用すると、次の Pro*C 例が示すようにraise_application_errorが戻す特定のエラー番号をアプリケーション独自の例外にマップできます。

EXEC SQL EXECUTE /* Execute embedded PL/SQL block using host variables my_emp_id and my_amount, which were assigned values in the host environment. */ DECLARE null_salary EXCEPTION; /* Map error number returned by raise_application_error to user-defined exception. */ PRAGMA EXCEPTION_INIT(null_salary, -20101); BEGIN raise_salary(:my_emp_id, :my_amount); EXCEPTION WHEN null_salary THEN INSERT INTO emp_audit VALUES (:my_emp_id, ...); END;END-EXEC;

この手法を使用すると、呼出し側のアプリケーションは、エラーが発生している状態を特定の例外ハンドラで処理できます。

事前定義の例外の再宣言事前定義の例外の再宣言事前定義の例外の再宣言事前定義の例外の再宣言PL/SQL は、事前定義の例外をパッケージ STANDARDでグローバルに宣言しているため、ユーザーが宣言する必要はありません。事前定義の例外を再宣言すると、ローカルな宣言がグローバルな宣言を上書きするために、エラーが発生しやすくなります。たとえば、invalid_number という名前の例外を宣言し、PL/SQL によって事前定義の例外INVALID_NUMBERが内部的に呼び出された場合、INVALID_NUMBER用に作成されたハンドラは内部例外を捕捉できません。この場合は、ドット表記法を使用して、次のように事前定義の例外を指定する必要があります。

EXCEPTION WHEN invalid_number OR STANDARD.INVALID_NUMBER THEN -- handle the errorEND;

PL/SQL エラーの処理 10-11

Page 318: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外の呼出し

PL/SQL 例外の呼出し例外の呼出し例外の呼出し例外の呼出し内部例外は実行時システムによって暗黙的に呼び出されます。これは、EXCEPTION_INITを使用して Oracle エラー番号に関連付けたユーザー定義の例外の場合も同じです。ただし、それ以外のユーザー定義の例外は、RAISE文で明示的に呼び出す必要があります。

RAISE 文を使用した例外の呼出し文を使用した例外の呼出し文を使用した例外の呼出し文を使用した例外の呼出しPL/SQL ブロックおよびサブプログラムから例外を呼び出すのは、エラーが原因で処理の完了が望ましくない場合または不可能な場合のみにする必要があります。指定した例外に対する RAISE文は、その例外の有効範囲の中ならば任意の場所に置くことができます。次の例では、PL/SQL ブロックで out_of_stockという名前のユーザー定義の例外を指定しています。

DECLARE out_of_stock EXCEPTION; number_on_hand NUMBER := 0;BEGIN IF number_on_hand < 1 THEN RAISE out_of_stock; -- raise an exception that we defined END IF;EXCEPTION WHEN out_of_stock THEN -- handle the error dbms_output.put_line('Encountered out-of-stock error.');END;/

事前定義の例外を明示的に呼び出すこともできます。これを利用すると、事前定義の例外のために書かれた例外ハンドラで、それ以外のエラーを処理させることができます。次に例を示します。

DECLARE acct_type INTEGER := 7;BEGIN IF acct_type NOT IN (1, 2, 3) THEN RAISE INVALID_NUMBER; -- raise predefined exception END IF;EXCEPTION WHEN INVALID_NUMBER THEN dbms_output.put_line('Handling invalid input by rolling back.'); ROLLBACK;END;/

10-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 319: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外の伝播

PL/SQL 例外の伝播例外の伝播例外の伝播例外の伝播例外が呼び出されたときに、PL/SQL がその例外のハンドラをカレント・ブロックまたはサブプログラムで発見できない場合、例外は伝播します。つまり、例外は外側のブロックで再生され、ハンドラが見つかるまで、または検索するブロックがなくなるまで、1 つずつ外側のブロックに進んでいきます。ハンドラが見つからなかった場合、PL/SQL はホスト環境に

「未処理例外」エラーを戻します。

例外はデータベース・リンクを通じて行われるリモート・プロシージャ・コールには伝播しません。そのため、PL/SQL ブロックは、リモート・サブプログラムによって呼び出された例外を処理できません。回避策の詳細は、10-10 ページの「独自のエラー・メッセージの定義 : RAISE_APPLICATION_ERROR プロシージャ」を参照してください。

図 10-1、図 10-2 および図 10-3 に、基本的な伝播規則を示します。

図図図図 10-1 伝播規則伝播規則伝播規則伝播規則 : 例例例例 1

PL/SQL エラーの処理 10-13

Page 320: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外の伝播

図図図図 10-2 伝播規則伝播規則伝播規則伝播規則 : 例例例例 2

10-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 321: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外の伝播

図図図図 10-3 伝播規則伝播規則伝播規則伝播規則 : 例例例例 3

例外は有効範囲を超えて、つまり宣言されたブロックを超えたところまで伝播することがあります。次の例を考えます。

BEGIN DECLARE ---------- sub-block begins past_due EXCEPTION; due_date DATE := trunc(SYSDATE) - 1; todays_date DATE := trunc(SYSDATE); BEGIN IF due_date < todays_date THEN RAISE past_due; END IF; END; ------------- sub-block endsEXCEPTION WHEN OTHERS THEN ROLLBACK;END;/

PL/SQL エラーの処理 10-15

Page 322: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL 例外の再呼出し

例外 past_dueが宣言されたブロックに例外ハンドラが存在しないため、例外は外側のブロックに伝播します。ただし、宣言された有効範囲がすでに存在しないため、外側のブロックは名前 PAST_DUEを参照できません。一度例外名が失われると、この例外を捕捉できるのは OTHERSハンドラにかぎられます。ユーザー定義の例外のハンドラがない場合は、呼出し側のアプリケーションは次のエラーを受け取ります。

ORA-06510: PL/SQL: unhandled user-defined exception

PL/SQL 例外の再呼出し例外の再呼出し例外の再呼出し例外の再呼出し例外の再呼出しとは、ローカルに処理した例外を、外側のブロックに渡すことです。たとえば、現在のブロックでトランザクションをロールバックし、エラーを外側のブロックの中でログする場合があります。

例外を再度呼び出すには、RAISE文で例外名を省略します。例外名の省略は、例外ハンドラの中でのみ許されます。

DECLARE salary_too_high EXCEPTION; current_salary NUMBER := 20000; max_salary NUMBER := 10000; erroneous_salary NUMBER;BEGIN BEGIN ---------- sub-block begins IF current_salary > max_salary THEN RAISE salary_too_high; -- raise the exception END IF; EXCEPTION WHEN salary_too_high THEN -- first step in handling the error dbms_output.put_line('Salary ' || erroneous_salary || ' is out of range.'); dbms_output.put_line('Maximum salary is ' || max_salary || '.'); RAISE; -- reraise the current exception END; ------------ sub-block endsEXCEPTION WHEN salary_too_high THEN -- handle the error more thoroughly erroneous_salary := current_salary; current_salary := max_salary; dbms_output.put_line('Revising salary from ' || erroneous_salary || 'to ' || current_salary || '.');END;/

10-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 323: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

呼び出された PL/SQL 例外の処理

呼び出された呼び出された呼び出された呼び出された PL/SQL 例外の処理例外の処理例外の処理例外の処理例外が呼び出されると、PL/SQL ブロックまたはサブプログラムの通常の実行は中止され、制御が例外処理部に移ります。例外処理部の書式を次に示します。

EXCEPTION WHEN exception_name1 THEN -- handler sequence_of_statements1 WHEN exception_name2 THEN -- another handler sequence_of_statements2 ... WHEN OTHERS THEN -- optional handler sequence_of_statements3END;

呼び出された例外を処理するには、例外ハンドラを作成します。個々のハンドラは、例外を指定する WHEN句に、その例外が呼び出されたときに実行される一連の文を続けたものです。これらの文を 後に、ブロックまたはサブプログラムの実行は終わります。制御は例外が呼び出された箇所に戻りません。つまり、処理を中止した位置からは再開できません。

オプションの OTHERS例外ハンドラは、必ずブロックまたはサブプログラムの 後のハンドラにする必要があります。OTHERS 例外ハンドラは、名前を付けなかったすべての例外のハンドラとして使用されます。このため、ブロックまたはサブプログラムが持てる OTHERSハンドラは 1 つのみです。

次の例で示すように、OTHERSハンドラを使用すると、すべての例外が処理されます。

EXCEPTION WHEN ... THEN -- handle the error WHEN ... THEN -- handle the error WHEN OTHERS THEN -- handle all other errorsEND;

2 つ以上の例外で、同じ一連の文を実行する場合は、WHEN句の中でキーワード ORで区切って例外名を並べてください。次に例を示します。

EXCEPTION WHEN over_limit OR under_limit OR VALUE_ERROR THEN -- handle the error

リスト中の例外のいずれかが呼び出されると、それに関連する一連の文が実行されます。キーワード OTHERSは例外名のリストの中では使用できず、単独で使用する必要があります。例外ハンドラの数に制限はなく、また、個々のハンドラは例外のリストを一連の文に関連付けることができます。ただし、例外名は PL/SQL ブロックまたはサブプログラムの例外処理部で一度しか使用できません。

PL/SQL エラーの処理 10-17

Page 324: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

呼び出された PL/SQL 例外の処理

PL/SQL 変数の通常の有効範囲規則が適用されるため、例外ハンドラの中ではローカル変数とグローバル変数が参照できます。ただし、カーソル FORループの内側で例外が呼び出されると、ハンドラに制御が移る前にカーソルは暗黙的にクローズされます。したがって、ハンドラでは明示カーソルの属性の値を参照できません。

宣言の中で呼び出された例外の処理宣言の中で呼び出された例外の処理宣言の中で呼び出された例外の処理宣言の中で呼び出された例外の処理宣言の中でも、初期化の式が間違っていると例外が呼び出される場合があります。たとえば、次の宣言では定数 credit_limitが 999 よりも大きい数値を格納できないため、例外が呼び出されます。

DECLARE credit_limit CONSTANT NUMBER(3) := 5000; -- raises an exceptionBEGIN NULL;EXCEPTION WHEN OTHERS THEN -- Cannot catch the exception. This handler is never called. dbms_output.put_line('Can''t handle an exception in a declaration.');END;/

宣言の中で呼び出された例外は、ただちに外側のブロックに伝播するため、現在のブロックの中のハンドラは呼び出された例外を捕捉できません。

ハンドラの中で呼び出された例外の処理ハンドラの中で呼び出された例外の処理ハンドラの中で呼び出された例外の処理ハンドラの中で呼び出された例外の処理例外ハンドラの中で例外が発生した場合、そのハンドラで例外を捕捉することはできません。このため、ハンドラの内側で呼び出された例外はただちに外側のブロックに伝播し、そこで再び呼び出されて、その新しい例外のハンドラが検索されます。それ以降の例外の伝播は通常どおりに行われます。次に例を示します。

EXCEPTION WHEN INVALID_NUMBER THEN INSERT INTO ... -- might raise DUP_VAL_ON_INDEX WHEN DUP_VAL_ON_INDEX THEN ... -- cannot catch the exceptionEND;

例外ハンドラへの分岐と例外ハンドラからの分岐例外ハンドラへの分岐と例外ハンドラからの分岐例外ハンドラへの分岐と例外ハンドラからの分岐例外ハンドラへの分岐と例外ハンドラからの分岐GOTO文では、例外ハンドラから外側のブロックに分岐できます。

ただし、GOTO文では例外ハンドラへは分岐できません。また、例外ハンドラからカレント・ブロックに分岐することもできません。

10-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 325: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

呼び出された PL/SQL 例外の処理

エラー・コードとエラー・メッセージの取得エラー・コードとエラー・メッセージの取得エラー・コードとエラー・メッセージの取得エラー・コードとエラー・メッセージの取得 : SQLCODE およびおよびおよびおよび SQLERRM例外ハンドラでは、組込みファンクション SQLCODEおよび SQLERRMを使用して、発生したエラーを確認し、関連するエラー・メッセージを取得できます。内部例外の場合、SQLCODEは Oracle エラーの番号を戻します。SQLCODEが戻す番号は負の値ですが、Oracleエラー「データが見つかりません。」の場合は例外で、+100 が戻されます。SQLERRMは対応するエラー・メッセージを戻します。メッセージの先頭には Oracle エラー・コードが示されています。

ユーザー定義の例外の場合、SQLCODEは +1 を戻し、SQLERRMはメッセージ「ユーザー定義の例外」を戻します。

ただし、EXCEPTION_INITプラグマを使用して例外名に Oracle エラー番号を関連付けた場合は、SQLCODEはエラー番号を戻し、SQLERRMは対応するエラー・メッセージを戻します。Oracle エラー・メッセージの長さは、エラー・コードおよびネストされたメッセージ、表や列の名前といったメッセージの挿入部分を含めて 512 文字以内です。

例外が呼び出されなければ、SQLCODEは 0(ゼロ)を戻し、SQLERRMはメッセージ「ORA-0000: 正常に完了しました。」を戻します。

SQLERRMにエラー番号を渡すことができます。このとき、SQLERRMはそのエラー番号に関連付けられたメッセージを戻します。SQLERRMに渡すエラー番号は負の値にしてください。

SQLERRMに正数を渡すと、必ず「ユーザー定義の例外」というメッセージが戻されます。+100を渡した場合は例外で、この場合 SQLERRMは「データが見つかりません。」というメッセージを戻します。SQLERRMに 0(ゼロ)を渡すと、常にメッセージ「正常に完了しました。」を戻します。

SQLCODEまたは SQLERRMは、SQL 文では直接使用できません。次の例に示すように、値をローカル変数に代入してから、その変数を SQL 文の中で使用する必要があります。

DECLARE err_msg VARCHAR2(100);BEGIN /* Get a few Oracle error messages. */ FOR err_num IN 1..3 LOOP err_msg := SUBSTR(SQLERRM(-err_num),1,100); dbms_output.put_line('Error number = ' || err_num); dbms_output.put_line('Error message = ' || err_msg); END LOOP;END;/

文字列ファンクション SUBSTRを使用しているため、SQLERRMの値を err_msgに代入しても、(切捨ての結果として発生する)VALUE_ERROR例外は呼び出されません。どの内部例外が呼び出されるかを通知するファンクション SQLCODEおよび SQLERRMは、特に OTHERS例外ハンドラで使用すると便利です。

PL/SQL エラーの処理 10-19

Page 326: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL エラーの処理のヒント

注意注意注意注意 : RESTRICT_REFERENCESプラグマを使用してストアド・ファンクションの純正度を示すとき、ファンクションが SQLCODEまたは SQLERRMをコールする場合は、WNPSおよびRNPS制約は指定できません。

未処理例外の捕捉未処理例外の捕捉未処理例外の捕捉未処理例外の捕捉発生した例外に対応するハンドラが発見できない場合、PL/SQL はホスト環境に「例外は処理されませんでした。」というエラーを戻します。その結果はホスト環境によって異なります。たとえば、Oracle プリコンパイラ環境では、失敗した SQL 文または PL/SQL ブロックがデータベースに加えた変更は、すべてロールバックされます。

未処理例外はサブプログラムにも影響を与えます。サブプログラムの実行が正常終了すると、PL/SQL は OUTパラメータに値を代入します。ただし、未処理例外が発生して実行が終了すると、PL/SQL は OUT パラメータに値を代入しません(NOCOPYパラメータではない場合)。また、ストアド・サブプログラムで未処理例外が発生して実行が失敗した場合、PL/SQL はそのサブプログラムが実行したデータベース処理をロールバックしません。

すべての PL/SQL プログラムの も上のレベルに OTHERSハンドラを置くと、未処理例外の発生を避けることができます。

PL/SQL エラーの処理のヒントエラーの処理のヒントエラーの処理のヒントエラーの処理のヒントここでは、柔軟性が高い 3 つの方法について説明します。

例外が呼び出された後に実行を続ける方法例外が呼び出された後に実行を続ける方法例外が呼び出された後に実行を続ける方法例外が呼び出された後に実行を続ける方法例外ハンドラを使用すると、ブロックを終了する前に致命的なエラーからリカバリできます。ただしハンドラの実行が終了すると、ブロックの実行も終了します。例外ハンドラから現在のブロックに戻ることはできません。次の例で、SELECT INTO文が ZERO_DIVIDEを呼び出した場合、INSERT文の実行は再開できません。

DECLARE pe_ratio NUMBER(3,1);BEGIN DELETE FROM stats WHERE symbol = 'XYZ'; SELECT price / NVL(earnings, 0) INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio);EXCEPTION WHEN ZERO_DIVIDE THEN NULL;END;/

10-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 327: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL エラーの処理のヒント

ある文の例外を処理してから、次の文に進むことができます。この場合、独立した例外ハンドラを持つ独立したサブブロックに文を入れます。サブブロックでエラーが発生すると、ローカルなハンドラが例外を処理します。サブブロックが終了すると、外側のブロックは、そのサブブロックの終了位置から実行を継続します。次の例を考えます。

DECLARE pe_ratio NUMBER(3,1);BEGIN DELETE FROM stats WHERE symbol = 'XYZ'; BEGIN ---------- sub-block begins SELECT price / NVL(earnings, 0) INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; EXCEPTION WHEN ZERO_DIVIDE THEN pe_ratio := 0; END; ---------- sub-block ends INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio);EXCEPTION WHEN OTHERS THEN NULL;END;/

この例では、SELECT INTO文が ZERO_DIVIDE例外を呼び出すと、ローカル・ハンドラが例外を捕捉して pe_ratioを 0(ゼロ)に設定します。ハンドラの実行が終わり、サブブロックが終了すると、実行は INSERT文から続けられます。

また、一部で失敗した可能性がある一連の DML 操作を実行し、操作全体が完了した後で例外を処理する方法もあります。11-17 ページの「%BULK_EXCEPTIONS 属性を持つFORALL 例外の処理」を参照してください。

トランザクションの再試行トランザクションの再試行トランザクションの再試行トランザクションの再試行例外が呼び出された場合、トランザクションを中止せずに、再試行する場合があります。その方法は、次のとおりです。

1. トランザクションをサブブロックに入れます。

2. そのサブブロックをループの中に入れ、トランザクションが繰り返して実行されるようにします。

3. トランザクションを開始する前にセーブポイントをマークします。トランザクションの実行に成功すると、コミットしてループを終了します。トランザクションの実行に失敗すると制御は例外ハンドラに移り、例外ハンドラはセーブポイントまでロールバックして変更をすべて取り消し、問題点を修正します。

PL/SQL エラーの処理 10-21

Page 328: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL エラーの処理のヒント

次の例では、INSERT文で一意の列に重複する値を挿入しようとしたため、例外が呼び出されます。この例では、一意である必要のある値を変更し、次のループ反復に進んでいます。INSERT 文での挿入が正常に完了すると、ただちにループを終了します。この方法で、FORループまたは WHILEループを使用して、試行の回数を制限することをお薦めします。

DECLARE name VARCHAR2(20); ans1 VARCHAR2(3); ans2 VARCHAR2(3); ans3 VARCHAR2(3); suffix NUMBER := 1;BEGIN FOR i IN 1..10 LOOP -- try 10 times BEGIN -- sub-block begins SAVEPOINT start_transaction; -- mark a savepoint /* Remove rows from a table of survey results. */ DELETE FROM results WHERE answer1 = 'NO'; /* Add a survey respondent's name and answers. */ INSERT INTO results VALUES (name, ans1, ans2, ans3); -- raises DUP_VAL_ON_INDEX if two respondents have the same name COMMIT; EXIT; EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK TO start_transaction; -- undo changes suffix := suffix + 1; -- try to fix problem name := name || TO_CHAR(suffix); END; -- sub-block ends END LOOP;END;/

ロケータ変数を使用した例外の位置の識別ロケータ変数を使用した例外の位置の識別ロケータ変数を使用した例外の位置の識別ロケータ変数を使用した例外の位置の識別INSERT文、DELETE文または UPDATE文のような一連の文に対して 1 つの例外ハンドラを使用すると、エラーの原因となった文がわからなくなる場合があります。どの文が失敗したかを知る必要がある場合は、ロケータ変数を使用します。

DECLARE stmt INTEGER; name VARCHAR2(100);BEGIN stmt := 1; -- designates 1st SELECT statement SELECT table_name INTO name FROM user_tables WHERE table_name LIKE 'ABC%'; stmt := 2; -- designates 2nd SELECT statement SELECT table_name INTO name FROM user_tables WHERE table_name LIKE 'XYZ%';

10-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 329: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコンパイル時の警告の概要

EXCEPTION WHEN NO_DATA_FOUND THEN dbms_output.put_line('Table name not found in query ' || stmt);END;/

PL/SQL のコンパイル時の警告の概要のコンパイル時の警告の概要のコンパイル時の警告の概要のコンパイル時の警告の概要プログラムの安全性を高め、実行時の問題を避けるには、特定の警告条件のチェックを有効にします。これらの条件は、エラーが発生したり、サブプログラムがコンパイルできなくなるほど重大ではありません。未定義の結果を生成したり、パフォーマンス問題を発生させる可能性のあるサブプログラム内の問題を指摘する場合もあります。

PL/SQL 警告メッセージを操作するには、PLSQL_WARNINGS初期化パラメータ、DBMS_WARNINGパッケージおよび USER/DBA/ALL_PLSQL_OBJECT_SETTINGSビューを使用します。

PL/SQL の警告カテゴリの警告カテゴリの警告カテゴリの警告カテゴリPL/SQL 警告メッセージはカテゴリに分類されているため、よく似た警告のグループをコンパイル時に抑制したり、表示することができます。カテゴリは次のとおりです。

SEVERE: パラメータのエイリアシング問題など、予期しない動作や誤った結果が発生する可能性がある条件のメッセージ。

PERFORMANCE: INSERT文で NUMBER列に VARCHAR2値が渡される場合など、パフォーマンス問題が発生する可能性がある条件のメッセージ。

INFORMATIONAL: 実行できないデッド・コードなど、パフォーマンスや正確性に影響はないが、コードのメンテナンス性の向上のために変更する可能性がある条件のメッセージ。

All キーワードはすべての警告メッセージを参照する簡単な方法です。

特定のメッセージを警告ではなく、エラーとして扱うこともできます。たとえば、警告メッセージ PLW-05003がコードの重大な問題を表している場合、PLSQL_WARNINGS設定に'ERROR:05003'を含めると、条件トリガーは警告メッセージではなくエラー・メッセージ

(PLS_05003)になります。エラー・メッセージが発行されると、コンパイルは失敗します。

PL/SQL エラーの処理 10-23

Page 330: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコンパイル時の警告の概要

PL/SQL 警告メッセージの制御警告メッセージの制御警告メッセージの制御警告メッセージの制御PL/SQL コンパイル時にデータベースで警告メッセージを発行させるには、初期化パラメータ PLSQL_WARNINGSを設定します。警告の全カテゴリ(ALL、SEVERE、INFORMATIONAL、PERFORMANCE)および特定のメッセージ番号を有効または無効にできます。また、条件の修正が必要な特定の警告をデータベースでコンパイル・エラーとして扱うこともできます。

このパラメータはシステム・レベルまたはセッション・レベルで設定できます。ALTER PROCEDURE文に含めることによって、1 回のコンパイル用にも設定できます。開発中にすべての警告を有効にしたり、本番のための配布時にすべての警告を無効にできます。また、不要なコードやパフォーマンスなどの問題が予想される特定のサブプログラムの開発中に、一部の警告を有効にすることもできます。

ALTER SYSTEM SET PLSQL_WARNINGS='ENABLE:ALL'; -- For debugging during development.ALTER SESSION SET PLSQL_WARNINGS='ENABLE:PERFORMANCE'; -- To focus on one aspect.ALTER PROCEDURE hello COMPILE PLSQL_WARNINGS='ENABLE:PERFORMANCE'; -- Recompile with extra checking.ALTER SESSION SET PLSQL_WARNINGS='DISABLE:ALL'; -- To turn off all warnings.-- We want to hear about 'severe' warnings, don't want to hear about 'performance'-- warnings, and want PLW-06002 warnings to produce errors that halt compilation.ALTER SESSION SET PLSQL_WARNINGS='ENABLE:SEVERE','DISABLE:PERFORMANCE','ERROR:06002';

PL/SQL サブプログラムのコンパイル中に警告メッセージが発行される場合がありますが、無名ブロックは警告を発行しません。

PLSQL_WARNINGSパラメータの設定は、コンパイルされた各サブプログラムとともに格納されます。CREATE OR REPLACE文でサブプログラムを再コンパイルする場合、そのセッションの現在の設定が使用されます。ALTER ... COMPILE文でサブプログラムを再コンパイルする場合は、REUSE SETTINGS句を文に含めるかどうかによって、現在のセッション設定か、サブプロラムとともに格納した元の設定のいずれかが使用されます。

コンパイル中に生成される警告を確認するには、SQL*Plus の SHOW ERRORSコマンドを使用するか、USER_ERRORSデータ・ディクショナリ・ビューを問い合せます。すべてのPL/SQL 警告メッセージには、接頭辞 PLWが付きます。

DBMS_WARNING パッケージの使用パッケージの使用パッケージの使用パッケージの使用PL/SQL サブプログラムをコンパイルする開発環境を作成している場合、DBMS_WARNINGパッケージ内のサブプログラムをコールすることで、PL/SQL 警告メッセージを制御できます。複数のネストした SQL*Plus スクリプトからなる複雑なアプリケーションでは、コンパイル時にこのパッケージを使用することで、サブプログラムごとに異なる警告設定を適用できます。このパッケージを一度コールして PLSQL_WARNINGSパラメータの現在の状態を保存し、パラメータを変更して特定のサブプログラム・セットをコンパイルしてから、元のパラメータ値をリストアできます。

10-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 331: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコンパイル時の警告の概要

たとえば、次のプロシージャには、削除できる不要なコードがあります。間違いの可能性や、デバッグ・フラグで意図的に隠された可能性もあります。したがって警告メッセージが必要な場合も必要ない場合もあります。

CREATE OR REPLACE PROCEDURE dead_codeAS x number := 10;BEGIN if x = 10 then x := 20; else x := 100; -- dead code (never reached) end if;END dead_code;/-- By default, the preceding procedure compiles with no errors or warnings.

-- Now enable all warning messages, just for this session.CALL DBMS_WARNING.SET_WARNING_SETTING_STRING('ENABLE:ALL' ,'SESSION');

-- Check the current warning setting.select dbms_warning.get_warning_setting_string() from dual;

-- When we recompile the procedure, we will see a warning about the dead code.ALTER PROCEDURE dead_code COMPILE;

参照参照参照参照 : 『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』の ALTER PROCEDUREパッケージと DBMS_WARNINGパッケージ、および『Oracle Database エラー・メッセージ』の PLW- メッセージに関する説明を参照してください。

PL/SQL エラーの処理 10-25

Page 332: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のコンパイル時の警告の概要

10-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 333: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL アプリケーションのパフォーマンスのチュー

11

PL/SQL アプリケーションのパフォーマンスのアプリケーションのパフォーマンスのアプリケーションのパフォーマンスのアプリケーションのパフォーマンスの

チューニングチューニングチューニングチューニング

この章では、効率的な PL/SQL コードを記述する方法および既存のコードを高速化する方法について説明します。

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

� PL/SQL でプログラムを 適化する方法(11-2 ページ)

� PL/SQL のパフォーマンス問題を回避するためのガイドライン(11-3 ページ)

� PL/SQL プログラムのプロファイルおよびトレース(11-8 ページ)

� DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)(11-9 ページ)

� PL/SQL での計算集中型プログラムの記述(11-24 ページ)

� EXECUTE IMMEDIATE およびカーソル変数を使用した動的 SQL のチューニング(11-25ページ)

� NOCOPY コンパイラ・ヒントを使用した PL/SQL プロシージャ・コールのチューニング(11-26 ページ)

� システム固有の実行のための PL/SQL コードのコンパイル(11-28 ページ)

� テーブル・ファンクションの概要(11-36 ページ)

ニング 11-1

Page 334: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL でプログラムを最適化する方法

PL/SQL でプログラムを最適化する方法でプログラムを最適化する方法でプログラムを最適化する方法でプログラムを最適化する方法10g より前のリリースの PL/SQL コンパイラは、パフォーマンスを 適化するための変更を行うことなく、作成されたコードを機械コードに変換していました。今回のリリースのPL/SQL では、コードのパフォーマンスが向上するように再調整する機能を持つ 適化コンパイラが使用されます。

この新しいオプティマイザを利用するための特別な操作は必要ありません。このオプティマイザは、デフォルトで使用可能です。まれに、オプティマイザのオーバーヘッドによって、非常に大規模なアプリケーションをコンパイルするときに時間が長くかかる場合があります。この場合、初期化パラメータ PLSQL_OPTIMIZE_LEVEL=1を設定して(デフォルト値は 2)、 適化レベルを低くすることもできます。また、非常にまれですが、例外動作が変更されて、例外が発生しなくなったり、予測よりも早く例外が発生するようになる場合もあります。PL_SQL_OPTIMIZE_LEVEL=0に設定すると、コードは再調整されません。

PL/SQL コードをチューニングする場合コードをチューニングする場合コードをチューニングする場合コードをチューニングする場合この章では、特に次の条件に該当する場合に有効な情報について説明します。

� 数学の計算を大量に実行するプログラム。PLS_INTEGER、BINARY_FLOATおよびBINARY_DOUBLEデータ型について検討します。

� PL/SQL 問合せからコールされ、数百万回実行される可能性があるファンクション。ファンクションをできるだけ効率的にするために、すべてのパフォーマンス機能を検討します。また、各行の結果を事前に計算して問合せ時間を短縮するファンクション索引について検討することをお薦めします。

� INSERT文、UPDATE文または DELETE文の処理、あるいは問合せのループに長時間を費やすプログラム。DML を発行する場合は FORALL文、問合せの場合は BULK COLLECT INTO句および RETURNING BULK COLLECT INTO句について検討します。

� 新の PL/SQL 言語機能を利用していない古いコード。(Oracle Database 10g では多くの点でパフォーマンスが改善されたため、以前のリリースのコードはすべてチューニングの対象になります。)

� SQL に直接渡されるだけの DDL 文(CREATE TABLEなど)を発行するのではなく、PL/SQL 処理に長時間を費やすプログラム。ネイティブ・コンパイルについて検討します。PL/SQL は多くの組込みデータベース機能で使用されるため、このチューニング機能をデータベース全体に適用して、自分のコードのみでなく、多くの面でパフォーマンスを改善できます。

チューニングに取りかかる前に、現在のシステムで、個々のサブプログラムの実行時間を計測します。Oracle Database 10g の PL/SQL には、多くの自動 適化機能があるため、チューニングしなくても、パフォーマンスが改善する場合があります。

11-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 335: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のパフォーマンス問題を回避するためのガイドライン

PL/SQL のパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドラインのパフォーマンス問題を回避するためのガイドラインPL/SQL ベースのアプリケーションのパフォーマンスが十分でない場合、その原因は通常、不適切な SQL 文の記述、プログラミング慣習の不徹底、PL/SQL の基本に対する不注意、共有メモリーの間違った使用などが考えられます。

PL/SQL コードでのコードでのコードでのコードでの CPU オーバーヘッドの回避オーバーヘッドの回避オーバーヘッドの回避オーバーヘッドの回避

SQL 文の最大限の効率化文の最大限の効率化文の最大限の効率化文の最大限の効率化

PL/SQL プログラムは比較的単純に見えますが、これは、ほとんどの処理が SQL 文で実行されるためです。処理が低速な SQL 文は、実行が低速になる主な原因となります。

SQL 文によってプログラムが低速になる場合は、次の手順を試します。

� 適切な索引を使用していることを確認します。状況に応じて、使用する索引の種類は異なります。索引の使用方法は、問合せでの様々な表のサイズ、各問合せでのデータの配布、および WHERE句で使用される列によって異なる場合があります。

� DBMS_STATSパッケージのサブプログラムを使用して、すべての表について 新の統計が存在することを確認します。

� 次のものを使用して、実行計画および SQL 文のパフォーマンスを分析します。

� EXPLAIN PLAN文

� TKPROFユーティリティを持つ SQL トレース機能

� Oracle Trace 機能

� 必要に応じて、SQL 文を記述しなおします。たとえば、問合せヒントを使用すると、不要な全表スキャンなどの問題を回避できます。

これらの方法の詳細は、『Oracle Database パフォーマンス・チューニング・ガイド』を参照してください。

次に示すように、PL/SQL 機能を利用して SQL 文のパフォーマンスを改善できる場合もあります。

� PL/SQL ループ内で SQL 文を実行している場合、INSERT文、UPDATE文および DELETE文のループのかわりに、FORALL文を使用することを検討します。

� 問合せの結果セットをループしている場合、単一の操作で結果セット全体をメモリーに格納する方法として、SELECT INTO文の BULK COLLECT句を使用することを検討します。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-3

Page 336: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のパフォーマンス問題を回避するためのガイドライン

ファンクション・コールの最大限の効率化ファンクション・コールの最大限の効率化ファンクション・コールの最大限の効率化ファンクション・コールの最大限の効率化不適切に記述されたサブプログラム(低速のソートや検索機能など)によって、パフォーマンスが低下する場合があります。次に示すように、サブプログラムに対する不要なコールを回避して、コードを 適化します。

� SQL 問合せ内でファンクションがコールされる場合、問合せ時に表にファンクション索引を作成することで、行ごとにファンクション値をキャッシュできます。CREATE INDEX文には少し時間がかかる場合もありますが、問合せは非常に高速になる可能性があります。

� SQL 問合せ内で列がファンクションに渡される場合、問合せではその列上で通常の索引を使用できません。また、ファンクションが(非常に大きい可能性がある)表の行ごとにコールされる可能性があります。次に示すように、問合せをネストして、内側の問合せで問合せ結果が少ない行数になるようにフィルタリングし、外側の問合せでファンクションが数回のみコールされるようにすることを検討します。

BEGIN-- Inefficient, calls my_function for every row. FOR item IN (SELECT DISTINCT(SQRT(department_id)) col_alias FROM employees) LOOP dbms_output.put_line(item.col_alias); END LOOP;

-- Efficient, only calls function once for each distinct value. FOR item IN ( SELECT SQRT(department_id) col_alias FROM ( SELECT DISTINCT department_id FROM employees) ) LOOP dbms_output.put_line(item.col_alias); END LOOP;END;/

OUTパラメータまたは IN OUTパラメータを使用する場合、PL/SQL は、例外が発生した場合に正しく動作するように、パフォーマンスのオーバーヘッドを追加します(OUTパラメータの元の値が保たれるように、OUTパラメータに値を割り当てた後で、未処理例外のためにサブプログラムを終了します)。

作成するプログラムにおいて、このような状況で OUTパラメータの値を保持する必要がない場合、NOCOPYキーワードをパラメータ宣言に追加して、パラメータを OUT NOCOPYまたは IN OUT NOCOPYと宣言できます。

この手法を使用すると、コレクション、大きい VARCHAR2値、LOB などの大量のデータをOUTパラメータに渡す場合の処理を、大幅に高速化することができます。

11-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 337: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のパフォーマンス問題を回避するためのガイドライン

また、この手法は、オブジェクト型のメンバー・サブプログラムにも適用できます。これらのサブプログラムがオブジェクト型の属性を変更する場合、すべての属性は、サブプログラムが終了するときにコピーされます。このオーバーヘッドを回避するために、メンバー・サブプログラムの 初のパラメータに対して、PL/SQL の暗黙的な宣言である SELF IN OUTを使用するかわりに、明示的に SELF IN OUT NOCOPYと宣言することができます。

ループの最大限の効率化ループの最大限の効率化ループの最大限の効率化ループの最大限の効率化

PL/SQL アプリケーションはループの周囲に構築されることが多いため、次に示すように、ループ自体およびループ内のコードを 適化することは重要です。

� 可能であれば、初期化または計算をループの外側に移動します。

� 一連の DML 文を発行するために、ループ構造を FORALL文で置換します。

� 結果セットをループして値を格納するかわりに、問合せで BULK COLLECT句を使用して、単一の操作で問合せ結果をメモリーに格納します。

� 結果セットを 2 回以上ループしたり、結果セットのループ時に他の問合せを発行する必要がある場合、元の問合せを改善して、目的の結果を正確に取得することが可能な場合があります。UNION、INTERSECT、MINUSおよび CONNECT BY問合せ演算子の使用を検討します。

� 問合せを他の問合せ内にネストして(副問合せという)、複数の段階でフィルタリングおよびソートを行うこともできます。たとえば、内側の WHERE句で PL/SQL ファンクションをコールすると、表の各行でファンクションが毎回コールされる可能性があります。かわりに、内側の問合せで結果セットが少ない行数になるようにフィルタリングして、外側の問合せでファンクションをコールすることができます。

組込み文字列ファンクションの使用組込み文字列ファンクションの使用組込み文字列ファンクションの使用組込み文字列ファンクションの使用

PL/SQL には、REPLACE、TRANSLATE、SUBSTR、INSTR、RPAD、LTRIMなどの高度に適化された文字列ファンクションが多数用意されています。これらの組込みファンクションは、通常の PL/SQL よりも効率的な低レベルのコードを使用します。

正規表現の検索に PL/SQL の文字列ファンクションを使用する場合、REGEXP_SUBSTRなどの組込み正規表現ファンクションを使用することを検討します。

条件テストにおける最低コストの条件の先頭への配置条件テストにおける最低コストの条件の先頭への配置条件テストにおける最低コストの条件の先頭への配置条件テストにおける最低コストの条件の先頭への配置

PL/SQL は、結果が判別できた時点でただちに論理式の評価を停止します(短絡評価といいます)。

ANDまたは ORで指定された複数の条件を評価する場合、 低コストの条件を 初に配置します。たとえば、ファンクションの戻り値をテストする前に、PL/SQL 変数の値を確認します。これは、PL/SQL がファンクションのコールをスキップできる場合があるためです。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-5

Page 338: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のパフォーマンス問題を回避するためのガイドライン

データ型変換の回数の最少化データ型変換の回数の最少化データ型変換の回数の最少化データ型変換の回数の最少化PL/SQL は実行時に、異なるデータ型を自動的に変換します。たとえば、PLS_INTEGER変数を NUMBER変数に代入すると、両者の内部表現は異なるため、変換が実行されます。

暗黙的な変換を回避することで、パフォーマンスが向上します。文字式では文字リテラル、数式では小数など、適切な型のリテラルを使用します。

次の例に示すように、整数リテラル 15は、加算前に Oracle の NUMBERに変換されます。浮動小数点リテラル 15.0は、NUMBERで表されるため、変換は必要ありません。

DECLARE n NUMBER; c CHAR(5);BEGIN n := n + 15; -- converted implicitly; slow n := n + 15.0; -- not converted; fast c := 25; -- converted implicitly; slow c := TO_CHAR(25); -- converted explicitly; still slow c := '25'; -- not converted; fastEND;/

変換の回数を可能なかぎり減らすには、変数の型を変更したり、異なるデータ型で表を設計しなおすことが必要となる場合があります。また、データを一度変換(INTEGER列からPLS_INTEGER変数への変換など)した後は、一貫してその PL/SQL 型を使用することもできます。

整数の算術計算での整数の算術計算での整数の算術計算での整数の算術計算での PLS_INTEGER またはまたはまたはまたは BINARY_INTEGER の使用の使用の使用の使用

ローカル整変数を宣言する必要がある場合は、PLS_INTEGERデータ型を使用します。PLS_INTEGERは、 も効率的な整数型です。PLS_INTEGER変数は、INTEGER値またはNUMBER値より格納サイズが小さく、PLS_INTEGER演算ではマシン算術計算が使用されます。

BINARY_INTEGERデータ型は、新しいコードでは PLS_INTEGERと同じくらい効率的ですが、同じコードを Oracle9i または Oracle8i データベース上で実行すると、PLS_INTEGERの方が高速です。

NUMBER型とそのサブタイプは特殊な内部形式で表され、パフォーマンスよりも移植性および任意の位取りと精度に重点を置いて設計されています。INTEGERサブタイプの場合も、小数点以下がない浮動小数点数として扱われます。NUMBER変数または INTEGER変数の演算では、ライブラリ・ルーチンへのコールが必要です。

パフォーマンスを重視するコードでは、INTEGER、NATURAL、NATURALN、POSITIVE、POSITIVEN、SIGNTYPEなどの、制約付きのサブタイプを使用しないようにします。この型の変数を計算で使用すると、実行時に余分なチェックが必要となります。

11-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 339: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のパフォーマンス問題を回避するためのガイドライン

浮動小数点の算術計算での浮動小数点の算術計算での浮動小数点の算術計算での浮動小数点の算術計算での BINARY_FLOAT およびおよびおよびおよび BINARY_DOUBLE の使用の使用の使用の使用

NUMBER型とそのサブタイプは特殊な内部形式で表され、パフォーマンスよりも移植性および任意の位取りと精度に重点を置いて設計されています。NUMBER変数または INTEGER変数の演算では、ライブラリ・ルーチンへのコールが必要です。

BINARY_FLOAT型および BINARY_DOUBLE型では、システム固有のマシン算術計算命令を使用することができ、科学的な処理など、大量の演算を行うアプリケーションではより適しています。また、これらの型の方が、データベースで必要な領域が少なくて済みます。

これらの型は、常に正確に小数値を表すわけではなく、NUMBER型とは異なる四捨五入処理が行われます。これらの型は、正確さが非常に重要な財務処理コードにはあまり適していません。

PL/SQL コードでのメモリー・オーバーヘッドの回避コードでのメモリー・オーバーヘッドの回避コードでのメモリー・オーバーヘッドの回避コードでのメモリー・オーバーヘッドの回避

VARCHAR2 変数宣言時の大きいサイズの指定変数宣言時の大きいサイズの指定変数宣言時の大きいサイズの指定変数宣言時の大きいサイズの指定

式の結果がどの程度のサイズになるかが不明な場合、VARCHAR2変数に大きいサイズを割り当てる必要がある場合があります。VARCHAR2変数を宣言する際に、256 や 1000 などのやや大きいサイズを予測して指定するよりも、32000 などの大きいサイズを指定する方が、実際にはメモリーを節約できます。PL/SQL の 適化機能によって、簡単にオーバーフローの問題を回避し、同時にメモリーも節約できます。VARCHAR2型変数には、2000 文字以上のサイズを指定します。PL/SQL は、変数が割り当てられるまで待機し、必要な量の記憶域のみを割り当てます。

関連するサブプログラムのパッケージへのグループ化関連するサブプログラムのパッケージへのグループ化関連するサブプログラムのパッケージへのグループ化関連するサブプログラムのパッケージへのグループ化

パッケージ・サブプログラムを初めてコールすると、パッケージ全体が共有メモリー・プールにロードされます。パッケージ内の関連するサブプログラムに対する 2 度目以降のコールでは、ディスク I/O が必要ないため実行速度が向上します。パッケージがメモリーからエージ・アウトされた場合は、再参照する前に再ロードする必要があります。

共有メモリー・プールのサイズを適切に設定すると、パフォーマンスを改善できます。頻繁に使用するパッケージを十分に保持でき、しかもメモリーが浪費されないサイズになるように設定してください。

共有メモリー・プールでのパッケージの確保共有メモリー・プールでのパッケージの確保共有メモリー・プールでのパッケージの確保共有メモリー・プールでのパッケージの確保

オラクル社が提供するパッケージ DBMS_SHARED_POOLを使用すると、頻繁にアクセスするパッケージを共有メモリー・プールに確保できます。パッケージを確保すると、Oracle で通常使用される LRU(Least Recently Used)アルゴリズムでもエージ・アウトされることはありません。パッケージは、プールの占有状態やパッケージへのアクセス頻度に関係なく、メモリーに残ります。

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

PL/SQL アプリケーションのパフォーマンスのチューニング 11-7

Page 340: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL プログラムのプロファイルおよびトレース

コンパイラの警告を回避するためのコードの改善コンパイラの警告を回避するためのコードの改善コンパイラの警告を回避するためのコードの改善コンパイラの警告を回避するためのコードの改善PL/SQL のコンパイラは、プログラムは動作しても、パフォーマンスが低くなる可能性がある場合に、警告を発行します。このような警告を受け取った場合、パフォーマンスが重要なコードでは、警告のアドバイスに従ってコードを変更し、コードをより効率的にします。

PL/SQL プログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレースプログラムのプロファイルおよびトレース開発する PL/SQL アプリケーションが大きくなるほど、パフォーマンスの問題を切り出すのは困難になります。PL/SQL には、実行時の動作をプロファイルし、パフォーマンスのボトルネックを識別できるように、プロファイラ API が用意されています。また、サーバー上でプログラムの実行をトレースするためのトレース API もあります。Oracle Trace を使用すると、サブプログラム別または例外ごとに実行をトレースできます。

プロファイラプロファイラプロファイラプロファイラ API の使用の使用の使用の使用 : DBMS_PROFILER パッケージパッケージパッケージパッケージプロファイラ API は、PL/SQL パッケージ DBMS_PROFILERとして実装され、ランタイム統計を収集して保存するサービスを提供します。情報はデータベース表に格納され、後で問合せできます。たとえば、PL/SQL の各行とサブプログラムの実行にかかる所要時間を知ることができます。

プロファイラを使用するには、プロファイル・セッションを開始し、十分な範囲のコードを取得できるまでアプリケーションを実行し、収集されたデータをデータベースにフラッシュし、プロファイル・セッションを停止します。

プロファイラによって、プログラムの実行がトレースされ、各行および各サブプログラムの所要時間が計算されます。収集されたデータを使用してパフォーマンスを改善できます。たとえば、低速のサブプログラムに改善の重点を置くことができます。

DBMS_PROFILERサブプログラムの詳細は、『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

収集されたパフォーマンス・データの分析収集されたパフォーマンス・データの分析収集されたパフォーマンス・データの分析収集されたパフォーマンス・データの分析

次に、特定のコード・セグメントの実行や特定のデータ構造へのアクセスに、他よりも時間がかかっている原因を判断します。パフォーマンス・データを問い合せて問題を探します。ほとんどの実行時間を占めているサブプログラムやパッケージに重点を置いて、SQL 文、ループ、再帰ファンクションなど、考えられるパフォーマンスのボトルネックを調べてください。

トレース・データを使用したパフォーマンス改善トレース・データを使用したパフォーマンス改善トレース・データを使用したパフォーマンス改善トレース・データを使用したパフォーマンス改善

分析結果に基づいて低速のアルゴリズムを書き直します。たとえば、データが急増したために、線形検索をバイナリ検索に置き換える必要が出てくることがあります。また、不適切なデータ構造によって生じた非効率な部分を探し、必要に応じてそのデータ構造を置き換えてください。

11-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 341: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

トレーストレーストレーストレース API の使用の使用の使用の使用 : DBMS_TRACE パッケージパッケージパッケージパッケージ大規模で複雑なアプリケーションの場合は、サブプログラム間のコールを追跡するのは困難です。トレース API でコードをトレースすると、サブプログラムの実行順序を確認できます。トレース API は PL/SQL パッケージ DBMS_TRACEとして実装され、サブプログラムまたは例外ごとに実行をトレースするサービスを提供します。

トレースを使用するには、トレース・セッションを開始し、アプリケーションを実行してから、トレース・セッションを停止します。プログラムを実行すると、トレース・データが収集され、データベース表に格納されます。

DBMS_TRACEサブプログラムの詳細は、『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

トレースの制御トレースの制御トレースの制御トレースの制御

大規模なアプリケーションをトレースすると、大量のデータが生成されて管理が困難になることがあります。必要であれば、トレースを起動する前に、トレース・データ収集用の特定のサブプログラムを選択し、収集されるデータ量を制限できます。

また、トレース・レベルも選択できます。たとえば、すべてのサブプログラムと例外をトレースするか、選択したサブプログラムと例外をトレースするように指定できます。

DML 文および問合せのループ・オーバーヘッドの削減文および問合せのループ・オーバーヘッドの削減文および問合せのループ・オーバーヘッドの削減文および問合せのループ・オーバーヘッドの削減((((FORALL およびおよびおよびおよび BULK COLLECT))))

PL/SQL は、DML や問合せなどの SQL 文を SQL エンジンへ送信して実行します。SQL は、結果データを PL/SQL に戻します。バルク SQL と総称される PL/SQL 言語機能を使用することによって、この PL/SQL と SQL 間の通信において、パフォーマンスのオーバーヘッドを 小化できます。FORALL文を使用すると、INSERT文、UPDATE文または DELETE文が、1 文ずつではなく、バッチで送信されます。BULK COLLECT句を使用すると、結果が SQLからバッチで戻されます。DML 文が 4 つ以上のデータベース行に影響する場合は、バルクSQL を使用するとパフォーマンスが向上します。

値を PL/SQL 変数に SQL 文で代入することを、バインドバインドバインドバインドと呼びます。PL/SQL バインド操作は、3 つのカテゴリに分類されます。

� インバインドインバインドインバインドインバインド PL/SQL 変数またはホスト変数が、INSERT文または UPDATE文によってデータベースに格納される場合。

� アウトバインドアウトバインドアウトバインドアウトバインド データベースの値が、INSERT文、UPDATE文または DELETE文のRETURNING句によって PL/SQL 変数またはホスト変数に代入される場合。

� 定義定義定義定義 データベースの値が、SELECT文または FETCH文によって PL/SQL 変数またはホスト変数に代入される場合。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-9

Page 342: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

バルク SQL は、VARRAY やネストした表などの PL/SQL コレクションを使用して、大量のデータを単一の操作でやり取りします。この処理はバルク・バインドバルク・バインドバルク・バインドバルク・バインドと呼ばれます。コレクションに 20 個の要素がある場合、バルク・バインドは単一の操作で、20 回分の SELECT文、INSERT文、UPDATE文または DELETE文に相当する処理を実行できます。問合せでは、任意の数の結果を戻すことができ、行ごとに FETCH文を指定する必要はありません。

INSERT文、UPDATE文および DELETE文をスピードアップするには、ループ構造ではなくPL/SQL の FORALL文内に SQL 文を記述します。

SELECT文をスピードアップするには、SELECT文で、INTOを使用するかわりに BULK COLLECT INTO句を指定します。

これらの文に関する構文と制限の詳細は、13-86 ページの「FORALL 文」および 13-162 ページの「SELECT INTO 文」を参照してください。

FORALL 文の使用文の使用文の使用文の使用キーワード FORALLを使用すると、複数の DML 文を非常に効率的に実行できます。汎用目的の FORループとは異なり、1 つの DML 文のみを繰り返すことができます。

完全な構文と制約については、13-86 ページの「FORALL 文」を参照してください。

この SQL 文では複数のコレクションを参照できますが、索引値が添字として使用される場合のみ、FORALLによってパフォーマンスが改善されます。

通常、境界には連続した索引番号の範囲を指定します。コレクション要素を削除した後などに索引番号が連続していない場合、INDICES OF句または VALUES OF句を使用して、実際に存在する索引値のみを反復できます。

INDICES OF句は、指定したコレクションの索引値全体、または下限から上限の境界内の索引値のみを反復します。

VALUES OF句は、BINARY_INTEGER型または PLS_INTEGER型によって索引付けされ、要素が BINARY_INTEGER型または PLS_INTEGER型であるコレクションを参照します。FORALL文は、このコレクションの要素によって指定される索引値を反復します。

例例例例 11-1 ループでのループでのループでのループでの DELETE 文の発行文の発行文の発行文の発行

この FORALL文は、3 つの DELETE文すべてを一度に SQL エンジンへ送信します。

CREATE TABLE employees2 AS SELECT * FROM employees;DECLARE TYPE NumList IS VARRAY(20) OF NUMBER; depts NumList := NumList(10, 30, 70); -- department numbersBEGIN FORALL i IN depts.FIRST..depts.LAST DELETE FROM employees2 WHERE department_id = depts(i); COMMIT;END;/DROP TABLE employees2;

11-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 343: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

例例例例 11-2 ループでのループでのループでのループでの INSERT 文の発行文の発行文の発行文の発行

次の例では、データの一部を PL/SQL コレクションにロードします。次に、コレクション要素をデータベース表に 2 回挿入しています。1 回目は FORループを使用し、2 回目はFORALL文を使用します。FORALLを使用する方が高速です。

CREATE TABLE parts1 (pnum INTEGER, pname VARCHAR2(15));CREATE TABLE parts2 (pnum INTEGER, pname VARCHAR2(15));DECLARE TYPE NumTab IS TABLE OF parts1.pnum%TYPE INDEX BY PLS_INTEGER; TYPE NameTab IS TABLE OF parts1.pname%TYPE INDEX BY PLS_INTEGER; pnums NumTab; pnames NameTab; iterations CONSTANT PLS_INTEGER := 500; t1 INTEGER; t2 INTEGER; t3 INTEGER;BEGIN FOR j IN 1..iterations LOOP -- load index-by tables pnums(j) := j; pnames(j) := 'Part No. ' || TO_CHAR(j); END LOOP; t1 := dbms_utility.get_time; FOR i IN 1..iterations LOOP -- use FOR loop INSERT INTO parts1 VALUES (pnums(i), pnames(i)); END LOOP; t2 := dbms_utility.get_time; FORALL i IN 1..iterations -- use FORALL statement INSERT INTO parts2 VALUES (pnums(i), pnames(i)); t3 := dbms_utility.get_time; dbms_output.put_line('Execution Time (secs)'); dbms_output.put_line('---------------------'); dbms_output.put_line('FOR loop: ' || TO_CHAR((t2 - t1)/100)); dbms_output.put_line('FORALL: ' || TO_CHAR((t3 - t2)/100)); COMMIT;END;/DROP TABLE parts1;DROP TABLE parts2;このブロックを実行すると、FORALLを使用するループの方が高速であることがわかります。

例例例例 11-3 コレクションの一部でのコレクションの一部でのコレクションの一部でのコレクションの一部での FORALL の使用の使用の使用の使用

FORALLループの境界は、必ずしもすべての要素に適用する必要はなく、コレクションの一部に適用できます。

CREATE TABLE employees2 AS SELECT * FROM employees;DECLARE TYPE NumList IS VARRAY(10) OF NUMBER;

PL/SQL アプリケーションのパフォーマンスのチューニング 11-11

Page 344: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

depts NumList := NumList(5,10,20,30,50,55,57,60,70,75);BEGIN FORALL j IN 4..7 -- use only part of varray DELETE FROM employees2 WHERE department_id = depts(j); COMMIT;END;/DROP TABLE employees2;

例例例例 11-4 連続していない索引値での連続していない索引値での連続していない索引値での連続していない索引値での FORALL の使用の使用の使用の使用

FORALL文でコレクションを使用する前に、コレクションから一部の要素を削除する必要がある場合があります。INDICES OF句は、残りの要素のみを反復して、疎コレクションを処理します。

元のコレクションを変更せずに、一部の要素のみを処理したり、要素を異なる順序で処理したり、または一部の要素を複数回処理する場合もあります。VALUES OF句を使用すると、要素全体を新しいコレクションにコピーする(その結果、場合によっては大量のメモリーが消費される)かわりに、元のコレクションの要素への「ポインタ」として機能する要素を持つ単純なコレクションを設定できます。

次の例では、任意のデータ(表名のセット)を保持するコレクションを作成します。要素の一部を削除すると、デフォルトの FORALL文では動作しない疎コレクションになります。プログラムは、INDICES OF句を指定した FORALL文を使用して、データを表に挿入します。次に、元のコレクションの特定の要素を指す 2 つのコレクションを新しく設定します。VALUES OF句を指定した FORALL文を使用して、名前の各セットを別のデータベース表に格納します。

-- Create empty tables to hold order detailsCREATE TABLE valid_orders (cust_name VARCHAR2(32), amount NUMBER(10,2));CREATE TABLE big_orders AS SELECT * FROM valid_orders WHERE 1 = 0;CREATE TABLE rejected_orders AS SELECT * FROM valid_orders WHERE 1 = 0;

DECLARE-- Make collections to hold a set of customer names and order amounts.

SUBTYPE cust_name IS valid_orders.cust_name%TYPE; TYPE cust_typ IS TABLe OF cust_name; cust_tab cust_typ;

SUBTYPE order_amount IS valid_orders.amount%TYPE; TYPE amount_typ IS TABLE OF NUMBER; amount_tab amount_typ;

-- Make other collections to point into the CUST_TAB collection. TYPE index_pointer_t IS TABLE OF PLS_INTEGER; big_order_tab index_pointer_t := index_pointer_t(); rejected_order_tab index_pointer_t := index_pointer_t();

11-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 345: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

PROCEDURE setup_data IS BEGIN -- Set up sample order data, including some invalid orders and some 'big' orders. cust_tab := cust_typ('Company 1','Company 2','Company 3','Company 4', 'Company 5'); amount_tab := amount_typ(5000.01, 0, 150.25, 4000.00, NULL); END;

BEGIN setup_data();

dbms_output.put_line('--- Original order data ---'); FOR i IN 1..cust_tab.LAST LOOP dbms_output.put_line('Customer #' || i || ', ' || cust_tab(i) || ': $' || amount_tab(i)); END LOOP;

-- Delete invalid orders (where amount is null or 0). FOR i IN 1..cust_tab.LAST LOOP IF amount_tab(i) is null or amount_tab(i) = 0 THEN cust_tab.delete(i); amount_tab.delete(i); END IF; END LOOP;

dbms_output.put_line('--- Data with invalid orders deleted ---'); FOR i IN 1..cust_tab.LAST LOOP IF cust_tab.EXISTS(i) THEN dbms_output.put_line('Customer #' || i || ', ' || cust_tab(i) || ': $' || amount_tab(i)); END IF; END LOOP;

-- Since the subscripts of our collections are not consecutive, we use-- FORALL...INDICES OF to iterate through the actual subscripts, rather than 1..COUNT. FORALL i IN INDICES OF cust_tab INSERT INTO valid_orders(cust_name, amount) VALUES(cust_tab(i), amount_tab(i));

-- Now let's process the order data differently. We'll extract 2 subsets-- and store each subset in a different table.

setup_data(); -- Initialize the CUST_TAB and AMOUNT_TAB collections again.

FOR i IN cust_tab.FIRST .. cust_tab.LAST LOOP

PL/SQL アプリケーションのパフォーマンスのチューニング 11-13

Page 346: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

IF amount_tab(i) IS NULL OR amount_tab(i) = 0 THEN rejected_order_tab.EXTEND; -- Add a new element to this collection. rejected_order_tab(rejected_order_tab.LAST) := i; -- And record the subscript from the original collection. END IF; IF amount_tab(i) > 2000 THEN big_order_tab.EXTEND; -- Add a new element to this collection. big_order_tab(big_order_tab.LAST) := i; -- And record the subscript from the original collection. END IF; END LOOP;

-- Now it's easy to run one DML statement on one subset of elements, and another DML statement on a different subset.

FORALL i IN VALUES OF rejected_order_tab INSERT INTO rejected_orders VALUES (cust_tab(i), amount_tab(i));

FORALL i IN VALUES OF big_order_tab INSERT INTO big_orders VALUES (cust_tab(i), amount_tab(i));

COMMIT;END;/-- Verify that the correct order details were stored.SELECT cust_name "Customer", amount "Valid order amount" FROM valid_orders;SELECT cust_name "Customer", amount "Big order amount" FROM big_orders;SELECT cust_name "Customer", amount "Rejected order amount" FROM rejected_orders;

DROP TABLE valid_orders;DROP TABLE big_orders;DROP TABLE rejected_orders;

11-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 347: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

FORALL がロールバックに与える影響がロールバックに与える影響がロールバックに与える影響がロールバックに与える影響

FORALL文では、SQL 文の実行によって未処理例外が発生した場合、前回の実行中に行われたすべてのデータベース変更はロールバックされます。ただし、呼び出された例外が捕捉され処理されると、変更は、各 SQL 文の実行の前にマークされた暗黙的なセーブポイントまでロールバックされます。前の実行の間に行われた変更は、ロールバックされません。たとえば、次のように部門番号と肩書きを格納するデータベース表を作成するとします。次に、肩書きを、より長い肩書きに変更します。この新しい値が長すぎてその列では使用できないため、2 番目の UPDATEは失敗します。この例外に対する処理は行われるため、 初のUPDATEはロールバックされず、変更はコミットされます。

CREATE TABLE emp2 (deptno NUMBER(2), job VARCHAR2(18));DECLARE TYPE NumList IS TABLE OF NUMBER; depts NumList := NumList(10, 20, 30);BEGIN INSERT INTO emp2 VALUES(10, 'Clerk'); INSERT INTO emp2 VALUES(20, 'Bookkeeper'); -- Lengthening this job title causes an exception. INSERT INTO emp2 VALUES(30, 'Analyst'); COMMIT;

FORALL j IN depts.FIRST..depts.LAST -- Run 3 UPDATE statements. UPDATE emp2 SET job = job || ' (Senior)' WHERE deptno = depts(j); -- raises a "value too large" exceptionEXCEPTION WHEN OTHERS THEN dbms_output.put_line('Problem in the FORALL statement.'); COMMIT; -- Commit results of successful updates.END;/DROP TABLE emp2;

%BULK_ROWCOUNT 属性を持つ属性を持つ属性を持つ属性を持つ FORALL による影響を受ける行カウントによる影響を受ける行カウントによる影響を受ける行カウントによる影響を受ける行カウントカーソル属性の SQL%FOUND、SQL%ISOPEN、SQL%NOTFOUNDおよび SQL%ROWCOUNTは、直前に実行された DML 文についての役に立つ情報を戻します。

SQLカーソルは、FORALLで使用するための複合属性 %BULK_ROWCOUNTを持ちます。この属性は、結合配列のように機能します。SQL%BULK_ROWCOUNT(i)には、INSERT文、UPDATE文または DELETE文の i 番目の実行によって処理された行数が格納されます。次に例を示します。

CREATE TABLE emp2 AS SELECT * FROM employees;DECLARE TYPE NumList IS TABLE OF NUMBER; depts NumList := NumList(30, 50, 60);BEGIN

PL/SQL アプリケーションのパフォーマンスのチューニング 11-15

Page 348: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

FORALL j IN depts.FIRST..depts.LAST DELETE FROM emp2 WHERE department_id = depts(j);-- How many rows were affected by each DELETE statement? FOR i IN depts.FIRST..depts.LAST LOOP dbms_output.put_line('Iteration #' || i || ' deleted ' || SQL%BULK_ROWCOUNT(i) || ' rows.'); END LOOP;END;/DROP TABLE emp2;FORALL文と %BULK_ROWCOUNT属性は同じ添字を使用します。たとえば、FORALLが 5~10の範囲を使用した場合は、%BULK_ROWCOUNTでも同じ範囲が使用されます。FORALL文で INDICES OF句を使用して疎コレクションを処理する場合、%BULK_ROWCOUNTは、対応する疎の添字を持ちます。FORALL文で VALUES OF句を使用して要素のサブセットを処理する場合、%BULK_ROWCOUNTは、索引コレクションの要素の値に対応する添字を持ちます。索引コレクションの要素が重複しているために一部の DML 文が同じ添字を使用して複数回発行される場合、%BULK_ROWCOUNTの対応する要素は、その添字を使用する DML 文によって影響を受けたすべての行の合計です。(INDICES OF句および VALUES OF句を使用する場合の %BULK_ROWCOUNTの解釈例については、http://otn.oracle.co.jp/tech/pl_sql/の PL/SQL サンプル・プログラムを参照してください。)

典型的な挿入操作は 1 行にのみ影響するため、通常、挿入の場合の %BULK_ROWCOUNTは 1です。INSERT ... SELECT構造体の場合は、%BULK_ROWCOUNTが 2 以上になる場合があります。たとえば、次の FORALL文は反復のたびに任意の数の行を挿入します。それぞれの反復後に、%BULK_ROWCOUNTは挿入された行数を戻します。

CREATE TABLE emp_by_dept AS SELECT employee_id, department_id FROM employees WHERE 1 = 0;DECLARE TYPE dept_tab IS TABLE OF departments.department_id%TYPE; deptnums dept_tab;BEGIN SELECT department_id BULK COLLECT INTO deptnums FROM departments;

FORALL i IN 1..deptnums.COUNT INSERT INTO emp_by_dept SELECT employee_id, department_id FROM employees WHERE department_id = deptnums(i);

FOR i IN 1..deptnums.COUNT LOOP-- Count how many rows were inserted for each department; that is,-- how many employees are in each department. dbms_output.put_line('Dept '||deptnums(i)||': inserted '|| SQL%BULK_ROWCOUNT(i)||' records'); END LOOP;

11-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 349: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

dbms_output.put_line('Total records inserted =' || SQL%ROWCOUNT);END;/DROP TABLE emp_by_dept;

FORALL文を実行した後で、スカラー属性の %FOUND、%NOTFOUNDおよび %ROWCOUNTも使用できます。たとえば、%ROWCOUNTは、SQL 文のすべての実行によって処理された行の総数を戻します。

%FOUNDと %NOTFOUNDは、SQL 文の 後の実行のみを参照します。%BULK_ROWCOUNTを使用すると、個々の実行に対する値を推論できます。たとえば、%BULK_ROWCOUNT(i)がゼロの場合、%FOUNDと %NOTFOUNDはそれぞれ、FALSEおよび TRUEになります。

%BULK_EXCEPTIONS 属性を持つ属性を持つ属性を持つ属性を持つ FORALL 例外の処理例外の処理例外の処理例外の処理PL/SQL には、FORALL文の実行中に呼び出される例外を処理するメカニズムが用意されています。このメカニズムによって、バルク・バインド操作では、例外に関する情報を保存して処理を継続できます。

エラーが発生した場合もバルク・バインドを完了させるには、FORALL文にキーワードSAVE EXCEPTIONSを(境界の後、DML 文の前に)追加します。

実行中に呼び出されたすべての例外は、レコードのコレクションを格納するカーソル属性%BULK_EXCEPTIONSに保存されます。各レコードには次の 2 つのフィールドがあります。

� %BULK_EXCEPTIONS(i).ERROR_INDEXには、例外が呼び出されたときに実行中だった FORALL文の「反復」が保持されます。

� %BULK_EXCEPTIONS(i).ERROR_CODEには、対応する Oracle エラー・コードが保持されます。

%BULK_EXCEPTIONSによって格納された値は常に、直前に実行された FORALL文を参照します。例外の数は、%BULK_EXCEPTIONS.COUNTに保存されます。添字の範囲は 1 ~COUNTです。

例外が発生した反復で使用されたコレクション要素を特定するために、処理を逆にたどる必要がある場合があります。たとえば、INDICES OF句を使用して疎コレクションを処理する場合、要素を 1 つずつ確認して、%BULK_EXCEPTIONS(i).ERROR_INDEXに対応する要素を検出する必要があります。VALUES OF句を使用して要素のサブセットを処理する場合、索引コレクション内で添字が %BULK_EXCEPTIONS(i).ERROR_INDEXに一致する要素を検出し、次にその要素の値を添字として使用して、元のコレクション内の誤った要素を検出する必要があります。(INDICES OF句および VALUES OF句を使用する場合に誤った要素を検出する方法の例については、http://otn.oracle.co.jp/tech/pl_sql/の PL/SQLサンプル・プログラムを参照してください。)

キーワード SAVE EXCEPTIONSを省略すると、例外が呼び出された時点で FORALL文の実行が停止します。その場合、SQL%BULK_EXCEPTIONS.COUNTは 1 を戻し、SQL%BULK_EXCEPTIONSにはレコードが 1 つのみ含まれます。実行中に例外が呼び出されなければ、SQL%BULK_EXCEPTIONS.COUNTは 0(ゼロ)を戻します。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-17

Page 350: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

例例例例 11-5 例外が発生しても継続するバルク操作例外が発生しても継続するバルク操作例外が発生しても継続するバルク操作例外が発生しても継続するバルク操作

次に、DML 操作でエラーが発生しても、停止せずに多数の DML 操作を実行する方法の例を示します。

CREATE TABLE emp2 AS SELECT * FROM employees;DECLARE TYPE NumList IS TABLE OF NUMBER;-- The zeros in this list will cause divide-by-zero errors. num_tab NumList := NumList(10,0,11,12,30,0,20,199,2,0,9,1); errors NUMBER; dml_errors EXCEPTION; PRAGMA exception_init(dml_errors, -24381);BEGIN-- SAVE EXCEPTIONS means don't stop if some DELETEs fail. FORALL i IN num_tab.FIRST..num_tab.LAST SAVE EXCEPTIONS DELETE FROM emp2 WHERE salary > 500000/num_tab(i);-- If any errors occurred during the FORALL SAVE EXCEPTIONS,-- a single exception is raised when the statement completes.EXCEPTION WHEN dml_errors THEN -- Now we figure out what failed and why. errors := SQL%BULK_EXCEPTIONS.COUNT; dbms_output.put_line('Number of DELETE statements that failed: ' || errors); FOR i IN 1..errors LOOP dbms_output.put_line('Error #' || i || ' occurred during '|| 'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX); dbms_output.put_line('Error message is ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); END LOOP;END;/DROP TABLE emp2;

この例では、iが 2、6、10 のときに、事前定義の例外 ZERO_DIVIDEが呼び出されています。FORALL文の後、SQL%BULK_EXCEPTIONS.COUNTは 3 を戻し、SQL%BULK_EXCEPTIONSの内容は (2,1476)、(6,1476) および (10,1476) となっています。Oracle エラー・メッセージを(コードを含めて)取得するために、SQL%BULK_EXCEPTIONS(i).ERROR_CODEの値を無効にし、その結果をエラー・レポート・ファンクション SQLERRMに渡しています。このファンクションでは負の数値が予測されています。次に出力を示します。

11-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 351: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

Number of errors is 3Error 1 occurred during iteration 2Oracle error is ORA-01476: 除数がゼロです。Error 2 occurred during iteration 6Oracle error is ORA-01476: 除数がゼロです。Error 3 occurred during iteration 10Oracle error is ORA-01476: 除数がゼロです。

BULK COLLECT 句を使用した、問合せ結果のコレクションへの取出し句を使用した、問合せ結果のコレクションへの取出し句を使用した、問合せ結果のコレクションへの取出し句を使用した、問合せ結果のコレクションへの取出し問合せでキーワード BULK COLLECTを使用すると、結果セットを非常に効率的に取り出すことができます。各行をループするかわりに、単一の操作で、結果を 1 つ以上のコレクションに格納できます。このキーワードは、SELECT INTO文、FETCH INTO文およびRETURNING INTO句で使用できます。

BULK COLLECT 句では、INTOリスト内のすべての変数はコレクションである必要があります。表の列には、スカラー値または複合値(オブジェクト型を含む)を格納できます。次の例では、ネストした表に、データベースの 2 つの列全体をロードします。

DECLARE TYPE NumTab IS TABLE OF employees.employee_id%TYPE; TYPE NameTab IS TABLE OF employees.last_name%TYPE; enums NumTab; -- No need to initialize the collections. names NameTab; -- Values will be filled in by the SELECT INTO. PROCEDURE print_results IS BEGIN dbms_output.put_line('Results:'); FOR i IN enums.FIRST .. enums.LAST LOOP dbms_output.put_line(' Employee #' || enums(i) || ': ' || names(i)); END LOOP; END;BEGIN SELECT employee_id, last_name -- Retrieve data for 10 arbitrary employees. BULK COLLECT INTO enums, names FROM employees WHERE ROWNUM < 11;-- The data has all been brought into memory by BULK COLLECT.-- No need to FETCH each row from the result set. print_results;

SELECT employee_id, last_name -- Retrieve approximately 20% of all rows BULK COLLECT INTO enums, names FROM employees SAMPLE (20); print_results;END;/

PL/SQL アプリケーションのパフォーマンスのチューニング 11-19

Page 352: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

コレクションは自動的に初期化されます。ネストした表および結合配列は、必要な数の要素を保持できるように拡張されます。VARRAY を使用する場合、すべての戻り値は、宣言したVARRAY のサイズに格納できる必要があります。要素は、索引 1 から、既存の要素を上書きしながら挿入されます。

BULK COLLECT INTO句の処理は FETCHループに類似しており、問合せに一致する行がない場合に NO_DATA_FOUND例外は発生しません。結果のネストした表または VARRAY がNULL かどうか、または結果の結合配列に要素が含まれているかどうかを確認する必要があります。

結果の表が無制限に拡張するのを防ぐために、疑似列 ROWNUMを使用して、処理される行の数を制限できます。または、SAMPLE句を使用して、行のランダムなサンプルを取り出すこともできます。

DECLARE TYPE SalList IS TABLE OF emp.sal%TYPE; sals SalList;BEGIN-- Limit the number of rows to 100. SELECT sal BULK COLLECT INTO sals FROM emp WHERE ROWNUM <= 100;-- Retrieve 10% (approximately) of the rows in the table. SELECT sal BULK COLLECT INTO sals FROM emp SAMPLE 10;

END;/

次の項に示すように、指定した数の行をカーソルから一度にフェッチすることで、非常にサイズが大きい結果セットを処理できます。

カーソルからのバルク・フェッチの例カーソルからのバルク・フェッチの例カーソルからのバルク・フェッチの例カーソルからのバルク・フェッチの例

例例例例 11-6 カーソルからカーソルからカーソルからカーソルから 1 つ以上のコレクションへのバルク・フェッチつ以上のコレクションへのバルク・フェッチつ以上のコレクションへのバルク・フェッチつ以上のコレクションへのバルク・フェッチ

1 つのカーソルから 1 つ以上のコレクションにフェッチできます。

DECLARE TYPE NameList IS TABLE OF employees.last_name%TYPE; TYPE SalList IS TABLE OF employees.salary%TYPE; CURSOR c1 IS SELECT last_name, salary FROM employees WHERE salary > 10000; names NameList; sals SalList; TYPE RecList IS TABLE OF c1%ROWTYPE; recs RecList;

PROCEDURE print_results IS BEGIN dbms_output.put_line('Results:');

11-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 353: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

IF names IS NULL OR names.COUNT = 0 THEN RETURN; -- Don't print anything if collections are empty. END IF; FOR i IN names.FIRST .. names.LAST LOOP dbms_output.put_line(' Employee ' || names(i) || ': $' || sals(i)); END LOOP; END;BEGIN dbms_output.put_line('--- Processing all results at once ---'); OPEN c1; FETCH c1 BULK COLLECT INTO names, sals; CLOSE c1; print_results;

dbms_output.put_line('--- Processing 7 rows at a time ---'); OPEN c1; LOOP FETCH c1 BULK COLLECT INTO names, sals LIMIT 7; EXIT WHEN c1%NOTFOUND; print_results; END LOOP;-- Loop exits when fewer than 7 rows are fetched. Have to-- process the last few. Need extra checking inside PRINT_RESULTS-- in case it is called when the collection is empty. print_results; CLOSE c1;

dbms_output.put_line('--- Fetching records rather than columns ---'); OPEN c1; FETCH c1 BULK COLLECT INTO recs; FOR i IN recs.FIRST .. recs.LAST LOOP-- Now all the columns from the result set come from a single record. dbms_output.put_line(' Employee ' || recs(i).last_name || ': $' || recs(i).salary); END LOOP;END;/

PL/SQL アプリケーションのパフォーマンスのチューニング 11-21

Page 354: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

例例例例 11-7 カーソルからレコードのコレクションへのバルク・フェッチカーソルからレコードのコレクションへのバルク・フェッチカーソルからレコードのコレクションへのバルク・フェッチカーソルからレコードのコレクションへのバルク・フェッチ

1 つのカーソルから複数レコードのコレクションにフェッチできます。

DECLARE TYPE DeptRecTab IS TABLE OF dept%ROWTYPE; dept_recs DeptRecTab; CURSOR c1 IS SELECT deptno, dname, loc FROM dept WHERE deptno > 10;BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO dept_recs;END;/

LIMIT 句を使用したバルク・フェッチ操作の対象行の制限句を使用したバルク・フェッチ操作の対象行の制限句を使用したバルク・フェッチ操作の対象行の制限句を使用したバルク・フェッチ操作の対象行の制限バルク FETCH文でのみ使用可能なオプションの LIMIT句を使用すると、データベースからフェッチされる行の数を制限できます。

次の例では、ループが繰り返されるたびに、FETCH文によって 10(またはそれ以下の)行が索引付き表 empnosにフェッチされます。前の値は上書きされます。

DECLARE TYPE NumTab IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; CURSOR c1 IS SELECT empno FROM emp; empnos NumTab; rows NATURAL := 10;BEGIN OPEN c1; LOOP /* The following statement fetches 10 rows (or less). */ FETCH c1 BULK COLLECT INTO empnos LIMIT rows; EXIT WHEN c1%NOTFOUND; ... END LOOP; CLOSE c1;END;/

11-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 355: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)

RETURNING INTO 句を使用したコレクションへの句を使用したコレクションへの句を使用したコレクションへの句を使用したコレクションへの DML 結果の取出し結果の取出し結果の取出し結果の取出し次に示すように、INSERT文、UPDATE文または DELETE文の RETURNING INTO句に BULK COLLECT句を使用できます。

CREATE TABLE emp2 AS SELECT * FROM employees;DECLARE TYPE NumList IS TABLE OF employees.employee_id%TYPE; enums NumList; TYPE NameList IS TABLE OF employees.last_name%TYPE; names NameList;BEGIN DELETE FROM emp2 WHERE department_id = 30 RETURNING employee_id, last_name BULK COLLECT INTO enums, names; dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows:'); FOR i IN enums.FIRST .. enums.LAST LOOP dbms_output.put_line('Employee #' || enums(i) || ': ' || names(i)); END LOOP;END;/DROP TABLE emp2;

FORALL とととと BULK COLLECT の併用の併用の併用の併用FORALL文と BULK COLLECT句を組み合せることができます。出力コレクションは、FORALL文が反復されるとともに構築されます。

次の例では、削除される各行の EMPNO値は、コレクション ENUMSに格納されます。コレクション DEPTSには 3 つの要素が存在するため、FORALL文は 3 回反復します。FORALL文によって発行される各 DELETEで 5 行ずつ削除される場合、削除された行の値を格納するコレクション ENUMSには、文が完了すると 15 の要素が保持されます。

CREATE TABLE emp2 AS SELECT * FROM employees;DECLARE TYPE NumList IS TABLE OF NUMBER; depts NumList := NumList(10,20,30); TYPE enum_t IS TABLE OF employees.employee_id%TYPE; TYPE dept_t IS TABLE OF employees.department_id%TYPE; e_ids enum_t; d_ids dept_t;BEGIN FORALL j IN depts.FIRST..depts.LAST DELETE FROM emp2 WHERE department_id = depts(j) RETURNING employee_id, department_id BULK COLLECT INTO e_ids, d_ids; dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows:'); FOR i IN e_ids.FIRST .. e_ids.LAST LOOP

PL/SQL アプリケーションのパフォーマンスのチューニング 11-23

Page 356: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での計算集中型プログラムの記述

dbms_output.put_line('Employee #' || e_ids(i) || ' from dept #' || d_ids(i)); END LOOP;END;/DROP TABLE emp2;

各実行によって戻された列の値は、前に戻された値に追加されます。FORALL文のかわりにFORループを使用する場合、戻り値のセットは、各 DELETE文によって上書きされます。

FORALL文では、SELECT ...BULK COLLECT文は使用できません。

バルク・バインドとホスト配列の併用バルク・バインドとホスト配列の併用バルク・バインドとホスト配列の併用バルク・バインドとホスト配列の併用クライアント側のプログラムは、無名 PL/SQL ブロックを使用してホスト配列をバルク・バインド入出力できます。これは、コレクションをデータベース・サーバーとの間でやり取りするのに も効率的な方法です。

ホスト配列は OCI や Pro*C プログラムなどのホスト環境で宣言され、PL/SQL コレクションと区別するためのコロンを接頭辞として付ける必要があります。次の例では、DELETE文に入力ホスト配列が使用されています。実行時に、無名 PL/SQL ブロックがデータベース・サーバーに送信されて、実行されます。

DECLARE ...BEGIN -- assume that values were assigned to the host array -- and host variables in the host environment FORALL i IN :lower..:upper DELETE FROM employees WHERE department_id = :depts(i); COMMIT;END;/

PL/SQL での計算集中型プログラムの記述での計算集中型プログラムの記述での計算集中型プログラムの記述での計算集中型プログラムの記述BINARY_FLOATおよび BINARY_DOUBLEデータ型を使用すると、浮動小数点計算を伴う科学アプリケーションなど、大量の演算を行う実用的な PL/SQL プログラムを記述できます。これらのデータ型は、多くのハードウェア・システム上でシステム固有の浮動小数点型とほぼ同様に動作し、IEEE-754 浮動小数点標準で示されるセマンティックを持ちます。

これらのデータ型で小数データを表す方法は、財務処理アプリケーションにはあまり適していません。財務処理アプリケーションの場合、小数部分が正確に表されることの方が、単にパフォーマンスが向上することよりも重要です。

PLS_INTEGERおよび BINARY_INTEGERデータ型は PL/SQL 専用のデータ型で、整数の算術計算の場合、SQL データ型の NUMBERまたは INTEGERより効率的です。PLS_INTEGERを使用して、整数の算術計算用に純粋な PL/SQL コードを記述したり、PL/SQL で操作できるように NUMBERまたは INTEGER値を PLS_INTEGERに変換できます。

11-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 357: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE およびカーソル変数を使用した動的 SQL のチューニング

以前のリリースでは、PLS_INTEGERは BINARY_INTEGERより効率的でした。今回のリリースでは、どちらのパフォーマンスも同程度です。ただし、以前のリリースのデータベースでコードを実行する場合は、PLS_INTEGERを使用する方が望ましい場合があります。

パッケージ内で、異なる数値パラメータを受け入れるための、オーバーロードされるプロシージャおよびファンクションを記述できます。数学ルーチンは、パラメータ

(BINARY_FLOAT、BINARY_DOUBLE、NUMBERおよび PLS_INTEGER)の種類に合わせて適化して、不要な変換を回避できます。

SQRT、SIN、COSなどの組込み数学ファンクションには、BINARY_FLOATパラメータおよび BINARY_DOUBLEパラメータを受け入れる、オーバーロードされる高速なファンクションがすでに用意されています。BINARY_FLOATおよび BINARY_DOUBLE型の変数をこのようなファンクションに渡したり、このようなファンクションに式を渡すときにTO_BINARY_FLOATまたは TO_BINARY_DOUBLEファンクションをコールすることによって、計算集中型コードをスピードアップできます。

EXECUTE IMMEDIATE およびカーソル変数を使用した動的およびカーソル変数を使用した動的およびカーソル変数を使用した動的およびカーソル変数を使用した動的 SQL ののののチューニングチューニングチューニングチューニング

たとえば汎用目的のレポート・ライターなど、プログラムによっては、文の正確なテキストが実行時まで判明しない場合、様々な SQL 文を構築および処理する必要があります。多くの場合、このような文は実行ごとに変わります。このような文は動的 SQL 文と呼ばれます。

以前は、動的 SQL 文を実行するには、提供されているパッケージ DBMS_SQLを使用する必要がありました。現在、PL/SQL 内では、どの種類の動的 SQL 文でも、システム固有の動的 SQL と呼ばれるインタフェースを使用して実行できます。これに関連する主な PL/SQL機能は、EXECUTE IMMEDIATE文およびカーソル変数(REF CURSORともいう)です。

システム固有の動的 SQL コードは、DBMS_SQLパッケージをコールする場合よりもサイズが小さくなり、処理速度も高速になります。次の例では、カーソル変数を宣言し、そのカーソル変数を動的 SELECT文と対応付けます。

DECLARE TYPE EmpCurTyp IS REF CURSOR; emp_cv EmpCurTyp; my_ename VARCHAR2(15); my_sal NUMBER := 1000; table_name VARCHAR2(30) := 'employees';BEGIN OPEN emp_cv FOR 'SELECT last_name, salary FROM ' || table_name || ' WHERE salary > :s' USING my_sal; CLOSE emp_cv;END;/

詳細は、第 7 章を参照してください。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-25

Page 358: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

NOCOPY コンパイラ・ヒントを使用した PL/SQL プロシージャ・コールのチューニング

NOCOPY コンパイラ・ヒントを使用したコンパイラ・ヒントを使用したコンパイラ・ヒントを使用したコンパイラ・ヒントを使用した PL/SQL プロシージャ・プロシージャ・プロシージャ・プロシージャ・コールのチューニングコールのチューニングコールのチューニングコールのチューニング

デフォルトでは、OUTパラメータと IN OUTパラメータは値によって渡されます。すべてのIN OUTパラメータの値は、サブプログラムの実行前にコピーされます。サブプログラムの実行中は、一時変数に出力パラメータ値が保持されます。サブプログラムが正常に終了した場合、この値は実パラメータにコピーされます。サブプログラムが未処理例外で終了した場合、元のパラメータは変更されません。

パラメータが、コレクション、レコード、オブジェクト型のインスタンスなどの大規模なデータ構造を表す場合、このコピー作業によって実行速度が遅くなり、メモリーが消費されます。特に、このオーバーヘッドは、オブジェクト・メソッドに対する各コールで発生します。メソッドが正常に終了した場合のみメソッドによる変更が適用されるように、一時コピーがすべての属性に対して作成されます。

このオーバーヘッドを回避するには、NOCOPYヒントを指定します。これによって、PL/SQL コンパイラは OUTおよび IN OUTパラメータを参照によって渡すことができます。サブプログラムが正常に終了した場合、動作は通常の場合と同じです。サブプログラムが例外によって終了した場合も、OUTおよび IN OUTパラメータ(またはオブジェクト属性)の値が変更されることがあります。この手法を使用する場合、サブプログラムですべての例外が処理されるようにします。

次の例では、IN OUTパラメータ MY_STAFFを参照によって渡すように、コンパイラに指示します。これによって、エントリの VARRAY をサブプログラムにコピーしてサブプログラムが終了することを回避できます。

DECLARE TYPE Staff IS VARRAY(200) OF Employee; PROCEDURE reorganize (my_staff IN OUT NOCOPY Staff) IS ...BEGIN NULL;END;/

次の例では、ローカルのネストした表に 25,000 レコードがロードされます。この表は、何も実行しない 2 つのローカル・プロシージャに渡されます。プロシージャへのコールでNOCOPYを使用する方が、時間がかかりません。

DECLARE TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE; emp_tab EmpTabTyp := EmpTabTyp(NULL); -- initialize t1 NUMBER; t2 NUMBER; t3 NUMBER; PROCEDURE get_time (t OUT NUMBER) IS BEGIN t := dbms_utility.get_time; END; PROCEDURE do_nothing1 (tab IN OUT EmpTabTyp) IS BEGIN NULL; END;

11-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 359: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

NOCOPY コンパイラ・ヒントを使用した PL/SQL プロシージャ・コールのチューニング

PROCEDURE do_nothing2 (tab IN OUT NOCOPY EmpTabTyp) IS BEGIN NULL; END;BEGIN SELECT * INTO emp_tab(1) FROM employees WHERE employee_id = 100; emp_tab.EXTEND(49999, 1); -- copy element 1 into 2..50000 get_time(t1); do_nothing1(emp_tab); -- pass IN OUT parameter get_time(t2); do_nothing2(emp_tab); -- pass IN OUT NOCOPY parameter get_time(t3); dbms_output.put_line('Call Duration (secs)'); dbms_output.put_line('--------------------'); dbms_output.put_line('Just IN OUT: ' || TO_CHAR((t2 - t1)/100.0)); dbms_output.put_line('With NOCOPY: ' || TO_CHAR((t3 - t2))/100.0);END;/

NOCOPY の制限の制限の制限の制限NOCOPYを使用することによって、パラメータのエイリアシングの可能性が高くなります。詳細は、8-30 ページの「サブプログラムのパラメータのエイリアシングの理解」を参照してください。

NOCOPYは、ディレクティブではなく、ヒントです。次の場合には、PL/SQL コンパイラはNOCOPYヒントを無視して、値によってパラメータを渡します。エラーは生成されません。

� 実パラメータが結合配列の要素である場合。この制限は、パラメータが結合配列全体の場合は適用されません。

� 実パラメータに、位取りや NOT NULLなどの制約がある場合。この制限は、サイズ制約付きの文字列には適用されません。この制限は、制約付きの要素またはコンポジット型の属性には拡張されません。

� 実パラメータと仮パラメータがレコードであり、いずれかまたは両方のレコードが%ROWTYPEまたは %TYPEを使用して宣言されており、レコード内の対応するフィールドの制約が異なる場合。

� 実パラメータと仮パラメータがレコードであり、実パラメータはカーソル FORループの索引として(暗黙的に)宣言されており、レコード内の対応するフィールドの制約が異なる場合。

� 実パラメータを渡すために、暗黙的なデータ型の変換が必要となる場合。

� サブプログラムが、データベース・リンクによって、または外部プロシージャとしてコールされる場合。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-27

Page 360: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

システム固有の実行のためのシステム固有の実行のためのシステム固有の実行のためのシステム固有の実行のための PL/SQL コードのコンパイルコードのコンパイルコードのコンパイルコードのコンパイルPL/SQL プロシージャをコンパイルして、共有ライブラリに常駐するシステム固有のコードにすると、プロシージャをスピードアップできます。プロシージャは C 言語のコードに変換されてから、通常の C コンパイラでコンパイルされ、Oracle プロセスにリンクされます。

この手法は、提供されている Oracle パッケージと独自に記述したプロシージャの両方に使用できます。この方法でコンパイルしたプロシージャは、共有サーバー構成(以前のマルチスレッド・サーバー)や Oracle Real Application Clusters などのすべてのサーバー環境で動作します。

はじめにはじめにはじめにはじめに

PL/SQL のネイティブ・コンパイルを初めて実行する場合は、本番環境の前に、まずテスト・データベースで試します。

データベースを PL/SQL のネイティブ・コンパイル用に構成する前に、常にデータベースをバックアップします。パフォーマンス上のメリットに比べて、余分なコンパイル時間のデメリットの方が大きい場合、バックアップからリストアする方が、解釈済モードで全体を再コンパイルするよりも、必要な時間が短い場合があります。

設定手順の一部では、DBA の認可レベルが必要です。一部の初期化パラメータの値を変更して、データベース・サーバーで(可能であればインスタンスのデータ・ファイルの近くに)新しいディレクトリを作成する必要があります。また、データベース・サーバーには Cコンパイラも必要です。クラスタの場合、コンパイラはノードごとに必要です。この手順を開発用マシン上でテストできる場合でも、通常、ネイティブ・コンパイルを本番サーバーで実行するには、DBA に協力を依頼する必要があります。

システム管理者に連絡を取り、オペレーティング・システムに必要な C コンパイラが存在すること、および C コンパイラのパスを確認します。vi などのテキスト・エディタを使用して、ファイル $ORACLE_HOME/plsql/spnc_commandsを開き、コマンドのテンプレートが正しいことを確認します。通常、設定を変更する必要はなく、設定が正しいことを確認するのみです。

PL/SQL のネイティブ・コンパイルを使用するかどうかの判断のネイティブ・コンパイルを使用するかどうかの判断のネイティブ・コンパイルを使用するかどうかの判断のネイティブ・コンパイルを使用するかどうかの判断

PL/SQL のネイティブ・コンパイルによって、計算集中型のプロシージャ操作のパフォーマンスは大幅に改善されます。このような操作の例には、データ・ウェアハウス・アプリケーションや、サーバー側でデータを大幅に変換して表示するアプリケーションなどがあります。このような場合、実行速度が 高 30% 向上する場合があります。

この手法では、PL/SQL からコールされる SQL 文は高速にならないため、SQL の実行に費やす時間の少ない計算集中型の PL/SQL プロシージャで も高い効果が得られます。PL/SQL のネイティブ・コンパイルを有効にしてパフォーマンスが改善される度合いは、テストによって確認できます。

ネイティブ・コンパイルを使用してプログラム・ユニットをコンパイルすると、デフォルトの解釈済モードを使用するよりも時間がかかります。コードを頻繁に再コンパイルする、開発サイクルの繁忙期には、ネイティブ・コンパイルを無効にしてもかまいません。

11-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 361: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

PL/SQL のネイティブ・コンパイルを使用するとデータベース操作で大幅にパフォーマンスが改善すると判断した場合、NATIVE設定を使用してデータベース全体をコンパイルすることをお薦めします。データベース内のすべての PL/SQL コードをコンパイルすると、作成したコードおよびすべての組込み PL/SQL パッケージへのコールがスピードアップします。

PL/SQL のネイティブ・コンパイルの動作のネイティブ・コンパイルの動作のネイティブ・コンパイルの動作のネイティブ・コンパイルの動作

ネイティブ・コンパイルを使用しない場合、各 PL/SQL プログラム・ユニットは、中間形式の機械可読コード(m コード)にコンパイルされます。m コードはデータベース・ディクショナリに格納され、実行時に解釈されます。

PL/SQL のネイティブ・コンパイルを使用する場合、PL/SQL 文は実行時に解釈が不要な Cコードへ変換され、実行時のパフォーマンスが改善されます。

PL/SQL は、コマンド・ファイル $ORACLE_HOME/plsql/spnc_commands、およびオペレーティング・システムでサポートされている C コンパイラとリンカーを使用し、変換された C コードをコンパイルして共有ライブラリにリンクします。共有ライブラリは、データ・ディクショナリ内に格納されるため、自動的にパックアップすることができ、削除されないように保護されます。共有ライブラリ・ファイルは、ファイルシステムにコピーされ、PL/SQL のサブプログラムの起動時にロードされて実行されます。このファイルがデータベースの停止中にファイルシステムから削除された場合、またはライブラリを格納するディレクトリを変更した場合、ファイルは自動的に再度抽出されます。

SQL 文をコールするだけの PL/SQL プログラム・ユニットの場合、あまり(またはまったく)高速化しないこともありますが、ネイティブ・コンパイルされた PL/SQL が、対応する解釈済コードより低速になることはありません。コンパイルされたコードは解釈済コードと同じライブラリをコールするため、動作は同じです。

spnc_commands ファイルの形式ファイルの形式ファイルの形式ファイルの形式

$ORACLE_HOME/plsqlディレクトリの spnc_commands ファイルには、各プログラムをコンパイルおよびリンクするコマンドのテンプレートが含まれています。%(src)などの一部の特殊な名前は事前定義されており、対応するファイル名で置換されます。$(ORACLE_HOME)変数は、Oracle ホーム・ディレクトリの位置で置換されます。#文字を先頭に付けて、コメント行を記載することもできます。このファイルには、すべての特殊な表記法について説明するコメントが記載されています。

spnc_commandsファイルには、C コンパイラの事前定義されたパスが記載されています。パスはオペレーティング・システムによって異なります。(オペレーティング・システムごとに特定のコンパイラがサポートされます。)ほとんどの場合、このパスを変更する必要はありませんが、システム管理者が C コンパイラを別の場所にインストールした場合は変更が必要な場合があります。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-29

Page 362: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

PL/SQL のネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータのネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータのネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータのネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータ

次の表は、PL/SQL のネイティブ・コンパイルを実行する前に設定する必要がある初期化パラメータの一覧です。これらの初期化パラメータは、システム・レベルでのみ設定可能で、ALTER SESSIONコマンドでは設定できません。ORACLE_HOMEなどの変数を値に使用することはできません。フル・パスを使用してください。

PL/SQL のネイティブ・コンパイルで使用するセッション・レベルの初期化パラメータのネイティブ・コンパイルで使用するセッション・レベルの初期化パラメータのネイティブ・コンパイルで使用するセッション・レベルの初期化パラメータのネイティブ・コンパイルで使用するセッション・レベルの初期化パラメータ

PLSQL_CODE_TYPEパラメータによって、PL/SQL コードに対してネイティブ・コンパイルまたは解釈のどちらを行うかが決定します。デフォルト設定は INTERPRETEDです。PL/SQL のネイティブ・コンパイルを有効にするには、PLSQL_CODE_TYPEの値を NATIVEに設定します。

データベース全体を NATIVEでコンパイルする場合は、システム・レベルでPLSQL_CODE_TYPEを設定することをお薦めします。

注意注意注意注意 : この項の例で示す PL/SQL のネイティブ・コンパイル用のシステム・パラメータ設定は、システムでサーバー・パラメータ・ファイル

(SPFILE)を使用することを想定しています。

テキスト初期化パラメータ・ファイル(PFILE または initsid.ora)を使用する場合、次の表に示すように初期化パラメータ・ファイルのパラメータを変更してください。

パラメータパラメータパラメータパラメータ 説明説明説明説明

PLSQL_NATIVE_LIBRARY_DIR ネイティブ・コンパイルされた PL/SQL コードを含む共有ラ

イブラリを格納するフル・パスおよびディレクトリの名前。

Optimal Flexible Architecture(OFA)規則に従って、共有ラ

イブラリのディレクトリを、データ・ファイルの格納場所のサブディレクトリとして作成することをお薦めします。

セキュリティ上の理由から、このディレクトリに対する書込み権限を持つユーザーは、oracleおよび rootのみにする

必要があります。

PLSQL_NATIVE_LIBRARY_SUBDIR_COUNT

PLSQL_NATIVE_LIBRARY_DIRパラメータで指定したディレ

クトリのサブディレクトリの数。

オプションです。ネイティブ・コンパイルされたプログラム・ユニットの数が 15000 を超える場合に使用します。この

オプションを設定する必要がある場合は、11-35 ページの

「PL/SQL のシステム固有のライブラリ用のサブディレクトリ

の設定」を参照してください。

11-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 363: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

次の構文を使用して、このパラメータを設定します。

alter session set plsql_code_type='NATIVE';alter session set plsql_code_type='INTERPRETED';alter system set plsql_code_type='NATIVE';alter system set plsql_code_type='INTERPRETED';

PL/SQL のネイティブ・コンパイルの設定方法および使用方法のネイティブ・コンパイルの設定方法および使用方法のネイティブ・コンパイルの設定方法および使用方法のネイティブ・コンパイルの設定方法および使用方法

ネイティブ・コンパイルを使用して 1 つ以上のサブプログラムをスピードアップする手順は、次のとおりです。

1. 前述のように、PLSQL_NATIVE_LIBRARY_DIR初期化パラメータと、オプションでPLSQL_NATIVE_LIBRARY_SUBDIR_COUNT初期化パラメータを設定します。

2. ALTER SYSTEMまたは ALTER SESSIONコマンドを使用するか、初期化ファイルを更新して、PLSQL_CODE_TYPEパラメータの値を NATIVEに設定します。

3. 次のいずれかの方法を使用して 1 つ以上のサブプログラムをコンパイルします。

� CREATE OR REPLACEを使用してサブプログラムを作成または再コンパイルします。

� COMPILEオプションを指定して ALTER PROCEDURE、ALTER FUNCTIONまたはALTER PACKAGEコマンドを使用して、サブプログラムまたはパッケージ全体を再コンパイルします。(また、ALTER文とともに PLSQL_CODE_TYPE = NATIVE句を使用して、セッション全体の初期化パラメータを変更することなく、特定のサブプログラムに対する動作を変更することもできます。)

� サブプログラムを削除して再作成します。

� オラクル社が提供するパッケージ・セットを作成する SQL*Plus スクリプトの 1 つを実行します。

� PLSQL_CODE_TYPE=NATIVEを指定し、構成済の初期化ファイルを使用してデータベースを作成します。データベースの作成中に、UTLIRPスクリプトが実行され、オラクル社が提供するパッケージがすべてコンパイルされます。

4. 処理が正常に実行されたかどうかを確認するために、データ・ディクショナリを問い合せて、プロシージャがシステム固有の実行用にコンパイルされたかどうかを調べることができます。既存のプロシージャがシステム固有の実行用にコンパイルされたかどうかをチェックするには、データ・ディクショナリ・ビューUSER_PLSQL_OBJECT_SETTINGS、DBA_PLSQL_OBJECT_SETTINGSおよびALL_PLSQL_OBJECT_SETTINGSを問い合せます。たとえば、プロシージャ MY_PROCのステータスをチェックするには、次のように入力します。

参照参照参照参照 : 初期化パラメータとデータ・ディクショナリ・ビューの詳細は、『Oracle Database リファレンス』を参照してください。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-31

Page 364: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

CREATE OR REPLACE PROCEDURE my_proc AS BEGIN NULL; END;/SELECT plsql_code_type FROM user_plsql_object_settings WHERE name = 'MY_PROC';DROP PROCEDURE my_proc;

CODE_TYPE列の値は、プロシージャがシステム固有の実行用にコンパイルされていれば NATIVE、それ以外の場合は INTERPRETEDとなります。

プロシージャをコンパイルして共有ライブラリに入れると、Oracle プロセスに自動的にリンクされます。データベースを再起動したり、共有ライブラリを別の場所に移動する必要はありません。ストアド・プロシージャがすべて解釈されたか、すべてシステム固有の実行用にコンパイルされたか、または両者を組み合せてコンパイルされたかにかかわらず、ストアド・プロシージャを任意にコールできます。

依存性、無効化および再評価依存性、無効化および再評価依存性、無効化および再評価依存性、無効化および再評価

サブプログラムが無効になった場合(サブプログラムが依存する表が再作成された場合など)、再コンパイルが自動的に行われます。

ネイティブ・コンパイルされた PL/SQL サブプログラムが依存するオブジェクトが変更されると、サブプログラムは無効になります。同じサブプログラムが次にコールされたとき、データベースはサブプログラムを自動的に再コンパイルします。PLSQL_CODE_TYPE設定はサブプログラムごとにライブラリ・ユニットに格納されるため、自動再コンパイルではこの格納された設定をコード型として使用します。

格納された設定は、再評価の一部として再コンパイルが行われるときにのみ使用されます。SQL コマンドの create or replaceまたは alter...compileを使用して PL/SQL サブプログラムを明示的にコンパイルする場合、現在のセッション設定が使用されます。

生成された共有ライブラリは、SYSTEM表領域のデータベースに格納されます。ネイティブ・コンパイルされたプロシージャを初めて実行すると、対応する共有ライブラリが、データベースから PLSQL_NATIVE_LIBRARY_DIR初期化パラメータで指定されたディレクトリにコピーされます。

PL/SQL のネイティブ・コンパイルに使用するデータベースの設定のネイティブ・コンパイルに使用するデータベースの設定のネイティブ・コンパイルに使用するデータベースの設定のネイティブ・コンパイルに使用するデータベースの設定

この項で示す手順を使用して、PL/SQL のネイティブ・コンパイル用にデータベース全体を設定します。多くのデータベース操作で使用されるすべての組込み PL/SQL パッケージで、パフォーマンスが改善します。

PL/SQL のネイティブ・コンパイルで使用する新しいデータベースの作成のネイティブ・コンパイルで使用する新しいデータベースの作成のネイティブ・コンパイルで使用する新しいデータベースの作成のネイティブ・コンパイルで使用する新しいデータベースの作成

Database Configuration Assistant を使用する場合、Database Configuration Assistant で、PL/SQL のネイティブ・コンパイルに必要な初期化パラメータを設定します(11-30 ページの「PL/SQL のネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータ」を参照)。

使用するオペレーティング・システムでサポートされている C コンパイラを確認するには、そのオペレーティング・システム用のインストレーション・ガイドのプリコンパイラとツー

11-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 365: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

ルの制約および要件に関する表を参照してください。システム管理者に連絡し、システム上での C コンパイラの場所を確認します。このパスが spnc_commandsファイルに正しく指定されていることを確認する必要があります。

PL/SQL プログラム・ユニットの数を確認し、プログラム・ユニットが多すぎるためにPLSQL_NATIVE_DIR_SUBDIR_COUNT初期化パラメータを設定する必要があるかどうかを判断します。必要に応じて、PL/SQL のシステム固有のライブラリ用にサブディレクトリを作成します。デフォルトでは、PL/SQL プログラム・ユニットは 1 つのディレクトリに保持されます。プログラム・ユニット数が 15,000 を超える場合、オペレーティング・システムでパフォーマンスの低下が発生します。この問題に対処するには、PL/SQL プログラム・ユニットを複数のサブディレクトリに分散させることをお薦めします。

テスト・データベースを設定した場合、次の SQL 問合せによって、使用している PL/SQLプログラム・ユニットの数を判断します。

select count (*) from DBA_PLSQL_OBJECTS;

この問合せによって戻されるカウントが 15,000 を超える場合、11-35 ページの「PL/SQL のシステム固有のライブラリ用のサブディレクトリの設定」に示す手順を実行します。

PL/SQL のネイティブ・コンパイルで使用する既存のデータベースの変更のネイティブ・コンパイルで使用する既存のデータベースの変更のネイティブ・コンパイルで使用する既存のデータベースの変更のネイティブ・コンパイルで使用する既存のデータベースの変更

既存のデータベースをネイティブ・コンパイルするには、次の手順を実行します。

1. システム管理者に連絡を取り、オペレーティング・システムに必要な C コンパイラが存在すること、および C コンパイラのパスを確認します。vi などのテキスト・エディタを使用して、ファイル spnc_commandsを開き、コマンドのテンプレートが正しいことを確認します。

2. oracleユーザー権限で、Oracle データベースごとに、PL/SQL のシステム固有のライブラリ・ディレクトリを作成します。

注意注意注意注意 : Oracle データベースごとに PL/SQL ライブラリを設定する必要があります。共有ライブラリ(.soおよび .dllファイル)は、各データベースへ論理的に接続されます。データベース間で共有することはできません。PL/SQL ライブラリを設定して共有すると、データベースは破損します。

.soおよび .dllファイルに対する不正アクセスを防ぐために、OFA 規則に従って、保護された場所にディレクトリを作成します。

また、PL/SQL のネイティブ・コンパイルに使用されるコンパイラの実行可能ファイルが、適切な権限を持つユーザーによってのみ書込み可能であることを確認します。

共有ライブラリの元のコピーは、データベース内に格納されているため、データベースとともに自動的にバックアップされます。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-33

Page 366: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

3. SQL を使用して、PLSQL_NATIVE_LIBRARY_DIR初期化パラメータを、PL/SQL のシステム固有のライブラリへのフル・パスに設定します。

たとえば、PL/SQL のシステム固有のライブラリに使用するディレクトリのパスが/oracle/oradata/mydb/natlibの場合、次のように入力します。

alter system set plsql_native_library_dir='/oracle/oradata/mydb/natlib'

4. PLSQL_NATIVE_DIR_SUBDIR_COUNT初期化パラメータを設定する必要があるかどうかを判断します。必要に応じて、PL/SQL のシステム固有のライブラリ用にサブディレクトリを作成します。

デフォルトでは、PL/SQL プログラム・ユニットは 1 つのディレクトリに保持されます。ただし、プログラム・ユニット数が 15000 を超える場合、オペレーティング・システムでパフォーマンスの低下が発生します。この問題に対処するには、PL/SQL プログラム・ユニットを複数のサブディレクトリに分散させることをお薦めします。

既存のデータベースを新しいデータベースへ移植する場合、またはテスト・データベースを設定した場合、次の SQL 問合せによって、使用している PL/SQL プログラム・ユニットの数を判断します。

select count (*) from DBA_PLSQL_OBJECTS;

この問合せによって戻されるカウントが 15,000 を超える場合、11-35 ページの「PL/SQL のシステム固有のライブラリ用のサブディレクトリの設定」に示す手順を実行します。

5. 他の必要な初期化パラメータを、11-30 ページの「PL/SQL のネイティブ・コンパイルで使用するシステム・レベルの初期化パラメータ」の表に示すように設定します。

6. 次のストアド・プロシージャを作成して、PL/SQL のネイティブ・コンパイルが有効であることを確認します。

CREATE OR REPLACE PROCEDURE Hello ASBEGIN dbms_output.put_line ( 'This output is from a natively compiled procedure.' );END Hello;/

7. 次のようにストアド・プロシージャを実行します。

CALL Hello();

プログラムが適切な出力を戻さない場合、オラクル社カスタマ・サポート・センターに連絡してください。(プロシージャの実行前に SQL*Plus で SET SERVEROUTPUT ONを設定することに注意してください。)

8. データベースのすべての PL/SQL サブプログラムを再コンパイルします。通常、スクリプト $ORACLE_HOME/admin/utlirp.sqlが使用されます。

11-34 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 367: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

システム固有の実行のための PL/SQL コードのコンパイル

PL/SQL のシステム固有のライブラリ用のサブディレクトリの設定のシステム固有のライブラリ用のサブディレクトリの設定のシステム固有のライブラリ用のサブディレクトリの設定のシステム固有のライブラリ用のサブディレクトリの設定

PL/SQL のシステム固有のライブラリ用にサブディレクトリを設定する必要がある場合は、次の手順を使用します。

1. サブディレクトリを d0、d1、d2、d3...dx と順番に作成します。ここで、x はディレクトリの総数です。このタスクには、スクリプトを使用することをお薦めします。たとえば、次のような PL/SQL ブロックを実行して、出力をファイルに保存してから、そのファイルをシェル・スクリプトとして実行することができます。

BEGIN FOR j IN 0..999 LOOP dbms_output.put_line ( 'mkdir d' || TO_CHAR(j) ); END LOOP;END;/

2. PLSQL_NATIVE_DIR_COUNT初期化パラメータに、作成したサブディレクトリの数を設定します。たとえば、1000 のサブディレクトリを作成した場合は、次の SQL 文をSQL*Plus に入力します。

alter system set plsql_native_library_subdir_count=1000;

例例例例 11-8 システム固有の実行のためのシステム固有の実行のためのシステム固有の実行のためのシステム固有の実行のための PL/SQL プロシージャのコンパイルプロシージャのコンパイルプロシージャのコンパイルプロシージャのコンパイル

alter session set plsql_code_type='NATIVE';CREATE OR REPLACE PROCEDURE hello_nativeASBEGIN dbms_output.put_line('Hello world.'); dbms_output.put_line('Today is ' || TO_CHAR(SYSDATE) || '.');END;/select plsql_code_type from user_plsql_object_settings where name = 'HELLO_NATIVE';alter session set plsql_code_type='INTERPRETED';

プロシージャはただちにコールできるようになり、Oracle プロセス内で共有ライブラリとして直接実行されます。コンパイル時にエラーが発生した場合、USER_ERRORSビューまたはSQL*Plus の SHOW ERRORSコマンドを使用して、エラーを確認できます。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-35

Page 368: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

ネイティブ・コンパイルの制限ネイティブ・コンパイルの制限ネイティブ・コンパイルの制限ネイティブ・コンパイルの制限� PL/SQL 用のデバッグ・ツールでは、システム固有の実行用にコンパイルされたプロ

シージャは処理されません。

� 多数のプロシージャとパッケージ(通常は 15000 以上)をシステム固有の実行用にコンパイルすると、単一のディレクトリに多数の共有オブジェクトができるため、システムのパフォーマンスに影響することがあります。回避策の詳細は、11-35 ページの

「PL/SQL のシステム固有のライブラリ用のサブディレクトリの設定」を参照してください。

Real Application Clusters およびおよびおよびおよび PL/SQL のネイティブ・コンパイルのネイティブ・コンパイルのネイティブ・コンパイルのネイティブ・コンパイル

クラスタではすべてのノードで PL/SQL のサブプログラムをコンパイルすることが必要な場合があるため、クラスタの各ノードで C コンパイラが必要です。また、各ノードの$ORACLE_HOME/plsql/spnc_commandsファイルで、設定およびパスを適切に指定する必要があります。

Real Application Clusters(RAC)環境で PL/SQL のネイティブ・コンパイルを使用する場合、共有ライブラリ・ファイルの元のコピーはデータベースに格納され、自動的にクラスタのすべてのノードに伝播されます。この機能を使用するためにライブラリをコピーする必要はありません。

この項の例でサーバー・パラメータ・ファイル(SPFILE)を使用するのは、RAC クラスタのすべてのノードが、PL/SQL のネイティブ・コンパイルを制御するパラメータで同じ設定を使用するためです。

テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定テーブル・ファンクションでの変換パイプラインの設定この項では、テーブル・ファンクションと呼ばれる特殊なファンクションを連鎖する方法について説明します。テーブル・ファンクションは、データ・ウェアハウスなどで複数の変換をデータに適用する場合に使用します。

主な項目は、次のとおりです。

� テーブル・ファンクションの概要

� パイプライン・テーブル・ファンクションの記述

テーブル・ファンクションの概要テーブル・ファンクションの概要テーブル・ファンクションの概要テーブル・ファンクションの概要テーブル・ファンクションは、物理データベース表と同様に問合せできるように、またはPL/SQL コレクション変数に代入できるように、行のコレクション(ネストした表またはVARRAY)を生成するファンクションです。テーブル・ファンクションは、問合せの FROM句にあるデータベース表の名前のように、または問合せの SELECTリストにある列名のように使用できます。

11-36 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 369: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

テーブル・ファンクションは、入力として行のコレクションを使用することができます。入力コレクション・パラメータには、コレクション型(VARRAYや PL/SQL 表など)またはREF CURSORを使用できます。

テーブル・ファンクションの実行はパラレル化でき、戻される行は中間のステージングなしで次のプロセスに直接送ることができます。テーブル・ファンクションから戻されるコレクションの行は、パイプライン化パイプライン化パイプライン化パイプライン化することもできます。つまり、テーブル・ファンクションの入力の処理がすべて完了してからバッチで戻されるのではなく、生成された時点で反復的に戻されます。

テーブル・ファンクションのストリーム、パイプラインおよびパラレル実行によって、次のようにパフォーマンスを改善できます。

� マルチスレッドが可能になり、テーブル・ファンクションを同時に実行します。

� プロセス間の中間的なステージングを排除します。

� 問合せの応答時間が短縮されます。パイプラインでないテーブル・ファンクションの場合は、問合せで 1 つの結果行を戻す前に、テーブル・ファンクションから戻されるコレクション全体を組み立てて、サーバーに戻す必要があります。パイプライン化によって、行を、生成時に反復的に戻すことができます。また、オブジェクト・キャッシュでコレクション全体をマテリアライズする必要がないため、テーブル・ファンクションのメモリー消費量も減少します。

� コレクション全体が表やメモリーにステージングされるまで待ってから、コレクション全体を戻すのではなく、各行の生成時にテーブル・ファンクションから戻されるコレクションの結果行を反復的に提供します。

例例例例 11-9 例例例例 : テーブル・ファンクションの問合せテーブル・ファンクションの問合せテーブル・ファンクションの問合せテーブル・ファンクションの問合せ

次の例のテーブル・ファンクション GetBooksは、入力として CLOBを取り、コレクション型 BookSet_tのインスタンスを戻します。CLOB列には、なんらかの形式(独自の、または XML などの標準に従った形式)で書籍のカタログ・リストが格納されています。このテーブル・ファンクションは、すべてのカタログとそれに対応する書籍リストを戻します。

コレクション型 BookSet_tの定義は、次のとおりです。

CREATE TYPE Book_t AS OBJECT ( name VARCHAR2(100), author VARCHAR2(30), abstract VARCHAR2(1000));/CREATE TYPE BookSet_t AS TABLE OF Book_t;/-- The CLOBs are stored in a table Catalogs:CREATE TABLE Catalogs ( name VARCHAR2(30), cat CLOB );

ファンクション GetBooksの定義は、次のとおりです。

CREATE FUNCTION GetBooks(a CLOB) RETURN BookSet_t;/

PL/SQL アプリケーションのパフォーマンスのチューニング 11-37

Page 370: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

次の問合せは、すべてのカタログとそれに対応する書籍リストを戻します。

SELECT c.name, Book.name, Book.author, Book.abstract FROM Catalogs c, TABLE(GetBooks(c.cat)) Book;

例例例例 11-10 例例例例 : テーブル・ファンクションの結果の代入テーブル・ファンクションの結果の代入テーブル・ファンクションの結果の代入テーブル・ファンクションの結果の代入

次の例は、テーブル・ファンクションの結果を PL/SQL コレクション変数に代入する方法を示しています。テーブル・ファンクションは問合せの SELECTリストからコールされるため、TABLEキーワードは不要です。

CREATE TYPE numset_t AS TABLE OF NUMBER;/

CREATE FUNCTION f1(x number) RETURN numset_t PIPELINED ISBEGIN FOR i IN 1..x LOOP PIPE ROW(i); END LOOP; RETURN;END;/

-- pipelined function in from clauseselect * from table(f1(3));

変換へのパイプライン・テーブル・ファンクションの使用変換へのパイプライン・テーブル・ファンクションの使用変換へのパイプライン・テーブル・ファンクションの使用変換へのパイプライン・テーブル・ファンクションの使用パイプライン・テーブル・ファンクションには、通常のファンクションに使用できる引数であれば、すべて使用できます。引数として REF CURSORを受け入れるテーブル・ファンクションは、変換ファンクションとして使用できます。つまり、REF CURSORを使用して入力行をフェッチし、その変換を実行し、結果をパイプラインで出力できます。

たとえば、次のコードは、StockPivotファンクションを定義する宣言を示しています。このファンクションは、(Ticker, OpenPrice, ClosePrice) 型の 1 行を (Ticker, PriceType, Price) 形式の 2 行に変換します。行 ("ORCL", 41, 42) についてStockPivotをコールすると、("ORCL", "O", 41) および ("ORCL", "C", 42) の 2 行が生成されます。

11-38 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 371: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

このテーブル・ファンクションの入力データを次の表 StockTableのようなソースから取り込むとします。

CREATE TABLE StockTable ( ticker VARCHAR(4), open_price NUMBER, close_price NUMBER);

これは宣言です。ファンクション本体については、11-40 ページの「テーブル・ファンクションからの結果の戻し」を参照してください

-- Create the types for the table function's output collection-- and collection elementsCREATE TYPE TickerType AS OBJECT( ticker VARCHAR2(4), PriceType VARCHAR2(1), price NUMBER);/

CREATE TYPE TickerTypeSet AS TABLE OF TickerType;/

-- Define the ref cursor type

CREATE PACKAGE refcur_pkg IS TYPE refcur_t IS REF CURSOR RETURN StockTable%ROWTYPE;END refcur_pkg;/

-- Create the table function

CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSetPIPELINED ... ;/

StockPivotテーブル・ファンクションを使用する問合せの例を次に示します。

SELECT * FROM TABLE(StockPivot(CURSOR(SELECT * FROM StockTable)));

この問合せでは、パイプライン・テーブル・ファンクション StockPivotは CURSOR副問合せ SELECT * FROM StockTableから行をフェッチし、変換を実行して、結果をパイプラインでユーザーに表として戻します。このファンクションでは、入力行ごとに出力行(コレクション要素)が 2 行ずつ生成されます。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-39

Page 372: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

CURSOR副問合せが前述の例のように SQL から REF CURSORファンクションの引数に渡される場合、ファンクションの実行中には参照先のカーソルがすでに開いています。

パイプライン・テーブル・ファンクションの記述パイプライン・テーブル・ファンクションの記述パイプライン・テーブル・ファンクションの記述パイプライン・テーブル・ファンクションの記述パイプライン・テーブル・ファンクションを宣言するには、PIPELINEDキーワードを指定します。このキーワードは、ファンクションが行を反復的に戻すことを示します。パイプライン・テーブル・ファンクションの戻り型は、ネストした表や VARRAY のようなコレクション型である必要があります。このコレクションはスキーマ・レベルまたはパッケージ内で宣言できます。ファンクション内では、コレクション型の個々の要素を戻します。

たとえば、次のような 2 つのパイプライン・テーブル・ファンクションの宣言を考えてみます。(ファンクション本体については、後の例を参照。)

CREATE FUNCTION GetBooks(cat CLOB) RETURN BookSet_t PIPELINED IS ...;/

CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSet PIPELINED IS...;/

テーブル・ファンクションからの結果の戻しテーブル・ファンクションからの結果の戻しテーブル・ファンクションからの結果の戻しテーブル・ファンクションからの結果の戻しPL/SQL では、PIPE ROW文によってテーブル・ファンクションで行がパイプされ、処理が継続します。この文を使用すると、PL/SQL のテーブル・ファンクションで生成直後に行を戻すことができます。(パフォーマンス上の理由から、PL/SQL ランタイム・システムでは、行はコンシューマにバッチで与えられます。)次に例を示します。

CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSetPIPELINED IS out_rec TickerType := TickerType(NULL,NULL,NULL); in_rec p%ROWTYPE;BEGIN LOOP FETCH p INTO in_rec; EXIT WHEN p%NOTFOUND; -- first row out_rec.ticker := in_rec.Ticker; out_rec.PriceType := 'O'; out_rec.price := in_rec.OpenPrice; PIPE ROW(out_rec); -- second row out_rec.PriceType := 'C'; out_rec.Price := in_rec.ClosePrice; PIPE ROW(out_rec);

11-40 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 373: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

END LOOP; CLOSE p; RETURN;END;/

この例で、PIPE ROW(out_rec)文はデータをパイプラインで PL/SQL テーブル・ファンクションから戻しています。out_recはレコードで、その型は出力コレクションの要素の型と一致します。

PIPE ROW文を使用できるのはパイプライン・テーブル・ファンクションの本体内のみで、他の場所で使用するとエラーが呼び出されます。行を戻さないパイプライン・テーブル・ファンクションの場合は、PIPE ROW文を省略できます。

パイプライン・テーブル・ファンクションには、値を戻さない RETURN文が必要です。このRETURN文は、制御をコンシューマに移し、次回のフェッチで NO_DATA_FOUND例外が確実に呼び出されるようにします。

テーブル・ファンクションとコール元のルーチンは、行の生成に伴って制御をやり取りするため、テーブル・ファンクションと PRAGMA AUTONOMOUS_TRANSACTIONの組合せに関する制限があります。テーブル・ファンクションが自律型トランザクションの一部である場合、コール元のサブプログラムでエラーが発生しないように、各 PIPE ROW文の前にCOMMITまたは ROLLBACKを実行する必要があります。

Oracle には、オブジェクトやコレクション型など、他の SQL 型の型記述、データ・インスタンスおよびデータ・インスタンス・セットを動的にカプセル化してアクセスできるように、3 つの特別なデータ型が用意されています。また、この 3 つの型を使用すると、匿名コレクション型のように匿名匿名匿名匿名の(つまり、名前を持たない)型を作成できます。この 3 つの型は、SYS.ANYTYPE、SYS.ANYDATAおよび SYS.ANYDATASETです。SYS.ANYDATA型は、テーブル・ファンクションからの戻り値として役立つ場合があります。

PL/SQL テーブル・ファンクション間のデータのパイプラインテーブル・ファンクション間のデータのパイプラインテーブル・ファンクション間のデータのパイプラインテーブル・ファンクション間のデータのパイプラインシリアル実行では、コルーチン実行に似たアプローチを使用して、結果がある PL/SQL テーブル・ファンクションから別の PL/SQL テーブル・ファンクションへとパイプラインされます。たとえば、次の文では、ファンクション gからファンクション fへと結果がパイプラインされます。

SELECT * FROM TABLE(f(CURSOR(SELECT * FROM TABLE(g()))));

パラレル実行の場合も同様ですが、各ファンクションは異なるプロセス(またはプロセス・セット)で実行されます。

参照参照参照参照 : ANYTYPE、ANYDATAおよび ANYDATASET型へのインタフェースと、この 3 つの型で使用する DBMS_TYPESパッケージについては、

『PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-41

Page 374: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

テーブル・ファンクションの問合せテーブル・ファンクションの問合せテーブル・ファンクションの問合せテーブル・ファンクションの問合せパイプライン・テーブル・ファンクションは、SELECT文の FROM句で使用されます。結果行は Oracle によってテーブル・ファンクションの実装から反復的に取り出されます。次に例を示します。

SELECT x.Ticker, x.PriceFROM TABLE(StockPivot( CURSOR(SELECT * FROM StockTable))) xWHERE x.PriceType='C';

テーブル・ファンクションに対する複数コールの最適化テーブル・ファンクションに対する複数コールの最適化テーブル・ファンクションに対する複数コールの最適化テーブル・ファンクションに対する複数コールの最適化テーブル・ファンクションを同じ問合せまたは別の問合せで複数回コールすると、基礎となる実装が複数回実行されます。デフォルトでは、行のバッファリングや再利用は行われません。

次に例を示します。

SELECT * FROM TABLE(f(...)) t1, TABLE(f(...)) t2 WHERE t1.id = t2.id;

SELECT * FROM TABLE(f());SELECT * FROM TABLE(f());

ファンクションが、渡される値の各組合せに対して常に同じ結果の値を生成する場合、ファンクション DETERMINISTICを宣言すると、Oracle によって行が自動的にバッファリングされます。ファンクションが実際は非決定的である場合、予測できない結果になります。

テーブル・ファンクションの結果からのフェッチテーブル・ファンクションの結果からのフェッチテーブル・ファンクションの結果からのフェッチテーブル・ファンクションの結果からのフェッチPL/SQL の CURSOR と REF CURSOR は、テーブル・ファンクションに対する問合せ用に定義できます。次に例を示します。

OPEN c FOR SELECT * FROM TABLE(f(...));

テーブル・ファンクションのカーソルと通常のカーソルでは、フェッチの意味は同じです。テーブル・ファンクションに基づく REF CURSORの代入に特別な意味はありません。

注意注意注意注意 : テーブル・ファンクションはコレクションを戻します。トップレベルの問合せで SELECT *が使用され、その問合せが PL/SQL 変数またはバインド変数を参照するような場合は、正確な戻り型を指定するために、表変数の周囲に CAST演算子が必要なことがあります。

11-42 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 375: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

ただし、SQL オプティマイザでは、PL/SQL 文にまたがる 適化は行われません。次に例を示します。

DECLARE r SYS_REFCURSOR;BEGIN OPEN r FOR SELECT * FROM TABLE(f(CURSOR(SELECT * FROM tab))); SELECT * BULK COLLECT INTO rec_tab FROM TABLE(g(r));END;/

前述の例は、次の例と同様には実行されません。

SELECT * FROM TABLE(g(CURSOR(SELECT * FROM TABLE(f(CURSOR(SELECT * FROM tab))))));

これは、2 つの SQL 文の実行に関連するオーバーヘッドを無視して、2 つの文の間で結果をパイプラインできると想定した場合も同様です。

カーソル変数によるデータの引渡しカーソル変数によるデータの引渡しカーソル変数によるデータの引渡しカーソル変数によるデータの引渡しPL/SQL ファンクションに REF CURSORパラメータで行セットを渡すことができます。たとえば、このファンクションが事前定義された弱い型指定の REF CURSORを持つSYS_REFCURSOR型の引数を受け入れるように宣言されているとします。

FUNCTION f(p1 IN SYS_REFCURSOR) RETURN ... ;

副問合せの結果をファンクションに直接渡すことができます。

SELECT * FROM TABLE(f(CURSOR(SELECT empno FROM tab)));

この例では、副問合せの結果を REF CURSORパラメータとして渡す必要があることを示すために、CURSORキーワードが必要です。

事前定義の弱い REF CURSOR型の SYS_REFCURSORもサポートされます。SYS_REFCURSORを使用すると、パッケージ内で REF CURSOR型を使用前に作成する必要はありません。

強い REF CURSOR型を使用する場合は、PL/SQL パッケージを作成し、その中で宣言する必要があります。また、強い REF CURSOR型をテーブル・ファンクションの引数として使用する場合は、REF CURSOR引数の実際の型が列の型と一致する必要があります。一致しない場合は、エラーが生成されます。テーブル・ファンクションの弱い REF CURSOR引数をパーティション化するには、PARTITION BY ANY句を使用する必要があります。弱い REF CURSOR引数には、レンジ・パーティション化もハッシュ・パーティション化も使用できません。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-43

Page 376: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

例例例例 11-11 例例例例 : 複数の複数の複数の複数の REF CURSOR 入力変数の使用入力変数の使用入力変数の使用入力変数の使用

PL/SQL ファンクションは、複数の REF CURSOR入力変数を受け入れることができます。

CREATE FUNCTION g(p1 pkg.refcur_t1, p2 pkg.refcur_t2) RETURN... PIPELINED ... ;/

ファンクション gは、次のようにコールできます。

SELECT * FROM TABLE(g(CURSOR(SELECT employee_id FROM tab), CURSOR(SELECT * FROM employees));

戻されたデータを反復する REF CURSORを作成すると、テーブル・ファンクションの戻り値を他のテーブル・ファンクションに渡すことができます。

SELECT * FROM TABLE(f(CURSOR(SELECT * FROM TABLE(g(...)))));

例例例例 11-12 例例例例 : 問合せに対する問合せに対する問合せに対する問合せに対する REF CURSOR の明示的オープンの明示的オープンの明示的オープンの明示的オープン

問合せに対して REF CURSORを明示的にオープンし、それをテーブル・ファンクションにパラメータとして渡すことができます。

DECLARE r SYS_REFCURSOR; rec ...;BEGIN OPEN r FOR SELECT * FROM TABLE(f(...)); -- Must return a single row result set. SELECT * INTO rec FROM TABLE(g(r));END;/

この場合、テーブル・ファンクションは完了時にカーソルをクローズするため、プログラムではカーソルを明示的にクローズしないようにする必要があります。

例例例例 11-13 例例例例 : 集計関数としてのパイプライン・テーブル・ファンクションの使用集計関数としてのパイプライン・テーブル・ファンクションの使用集計関数としてのパイプライン・テーブル・ファンクションの使用集計関数としてのパイプライン・テーブル・ファンクションの使用

テーブル・ファンクションでは、入力 REF CURSOR を使用して集計結果を計算できます。次の例では、一連の入力行を反復することで、加重平均を計算しています。

DROP TABLE gradereport;CREATE TABLE gradereport (student VARCHAR2(30), subject VARCHAR2(30), weight NUMBER, grade NUMBER);

INSERT INTO gradereport VALUES('Mark', 'Physics', 4, 4);INSERT INTO gradereport VALUES('Mark','Chemistry', 4,3);INSERT INTO gradereport VALUES('Mark','Maths', 3,3);INSERT INTO gradereport VALUES('Mark','Economics', 3,4);

11-44 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 377: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

CREATE OR replace TYPE gpa AS TABLE OF NUMBER;/

CREATE OR replace FUNCTION weighted_average(input_valuessys_refcursor)RETURN gpa PIPELINED IS grade NUMBER; total NUMBER := 0; total_weight NUMBER := 0; weight NUMBER := 0;BEGIN-- The function accepts a ref cursor and loops through all the input rows. LOOP FETCH input_values INTO weight, grade; EXIT WHEN input_values%NOTFOUND;-- Accumulate the weighted average. total_weight := total_weight + weight; total := total + grade*weight; END LOOP; PIPE ROW (total / total_weight);-- The function returns a single result. RETURN;END;/show errors;

-- The result comes back as a nested table with a single row.-- COLUMN_VALUE is a keyword that returns the contents of a nested table.select weighted_result.column_value from table( weighted_average( cursor(select weight,grade from gradereport) ) ) weighted_result;

テーブル・ファンクション内でのテーブル・ファンクション内でのテーブル・ファンクション内でのテーブル・ファンクション内での DML 操作の実行操作の実行操作の実行操作の実行DML 文を実行するには、AUTONOMOUS_TRANSACTIONプラグマを使用してテーブル・ファンクションを宣言します。これによって、ファンクションは、他のプロセスに共有されない新しいトランザクションで実行されます。

CREATE FUNCTION f(p SYS_REFCURSOR) return CollType PIPELINED IS PRAGMA AUTONOMOUS_TRANSACTION;BEGIN NULL; END;/

パラレル実行中に、テーブル・ファンクションの各インスタンスが独立したトランザクションを作成します。

PL/SQL アプリケーションのパフォーマンスのチューニング 11-45

Page 378: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

テーブル・ファンクションでの変換パイプラインの設定

テーブル・ファンクションへのテーブル・ファンクションへのテーブル・ファンクションへのテーブル・ファンクションへの DML 操作の実行操作の実行操作の実行操作の実行テーブル・ファンクションを UPDATE、INSERTまたは DELETE文のターゲット表にすることはできません。たとえば、次の文ではエラーが呼び出されます。

UPDATE F(CURSOR(SELECT * FROM tab)) SET col = value;INSERT INTO f(...) VALUES ('any', 'thing');

ただし、テーブル・ファンクションのビューを作成し、INSTEAD OFトリガーを使用して更新できます。次に例を示します。

CREATE VIEW BookTable AS SELECT x.Name, x.Author FROM TABLE(GetBooks('data.txt')) x;

次の INSTEAD OFトリガーは、ユーザーが BookTableビューに行を挿入すると起動します。

CREATE TRIGGER BookTable_insertINSTEAD OF INSERT ON BookTableREFERENCING NEW AS nFOR EACH ROWBEGIN ...END;/INSERT INTO BookTable VALUES (...);

INSTEAD OFトリガーは、テーブル・ファンクションに作成されたビューでのすべてのDML 操作について定義できます。

テーブル・ファンクションの例外処理テーブル・ファンクションの例外処理テーブル・ファンクションの例外処理テーブル・ファンクションの例外処理テーブル・ファンクションの例外処理は、通常のファンクションの場合と同じです。

C や Java など、一部の言語には、ユーザー指定の例外処理のためのメカニズムが用意されています。テーブル・ファンクション内で呼び出された例外が処理される場合に、テーブル・ファンクションは例外ハンドラを実行して処理を継続します。例外ハンドラを終了すると、制御が外側の有効範囲に移ります。例外が解消されると、実行は通常どおり進行します。

テーブル・ファンクションに未処理の例外があると、親トランザクションがロールバックされます。

11-46 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 379: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のオブジェクト

12

PL/SQL のオブジェクト型の使用のオブジェクト型の使用のオブジェクト型の使用のオブジェクト型の使用

オブジェクト指向プログラミングは、再利用可能なコンポーネントおよび複雑なアプリケーションを作成する場合に特に適しています。PL/SQL のオブジェクト指向のプログラミングは、オブジェクト型をベースにしています。オブジェクト型を使用することによって、実社会のオブジェクトをモデル化し、インタフェースと実装の細部を分離して、オブジェクト指向のデータをデータベースへ永続的に格納することが可能になります。Java または他のオブジェクト指向言語と相互作用するプログラムを記述する場合、オブジェクト型が有効な場合があります。

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

� PL/SQL のオブジェクト型の概要(12-2 ページ)

� オブジェクト型(12-2 ページ)

� オブジェクト型を使用する理由(12-4 ページ)

� オブジェクト型の構造(12-5 ページ)

� オブジェクト型の構成要素(12-6 ページ)

� オブジェクト型の定義(12-13 ページ)

� オブジェクトの宣言と初期化(12-15 ページ)

� オブジェクト属性へのアクセス(12-17 ページ)

� オブジェクト・コンストラクタの定義(12-18 ページ)

� オブジェクト・コンストラクタのコール(12-19 ページ)

� オブジェクト・メソッドのコール(12-20 ページ)

� REF 修飾子によるオブジェクトの共有(12-21 ページ)

� SQL を使用したオブジェクトの操作(12-23 ページ)

型の使用 12-1

Page 380: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のオブジェクト型の概要

PL/SQL のオブジェクト型の概要のオブジェクト型の概要のオブジェクト型の概要のオブジェクト型の概要この章を読む前に、次の基礎知識を理解しておく必要があります。

オブジェクト指向プログラミング。抽象化の概念も含まれます。

属性およびメソッドの概念。属性およびメソッドは、他の言語ではクラスの一部です。SQLおよび PL/SQL では、オブジェクト型の一部です。

SQL 文の CREATE TYPE。

Oracle のオブジェクト指向のすべての機能については、『Oracle Database アプリケーション開発者ガイド - オブジェクト・リレーショナル機能』を参照してください。この章の他の箇所では、PL/SQL 固有の問題について説明します。

オブジェクト型オブジェクト型オブジェクト型オブジェクト型オブジェクト型オブジェクト型オブジェクト型オブジェクト型は、データ構造と、データを操作するために必要なファンクションおよびプロシージャを表すユーザー定義の複合データ型です。スカラー・データ型では、各変数は 1つの値を保持します。コレクションでは、すべての要素は同じ型です。オブジェクト型のみが、コードとデータを関連付けることができます。

データ構造内の変数は、属性属性属性属性と呼ばれます。オブジェクト型のファンクションとプロシージャはメソッドメソッドメソッドメソッドと呼ばれます。

通常、オブジェクトは属性および動作を持つと考えられます。たとえば、赤ちゃんには性、年齢、体重などの属性があり、食べる、飲む、寝るなどの動作があります。オブジェクト型を使用すると、このような実世界の動作をアプリケーションで表現できます。

CREATE TYPE文を使用してオブジェクト型を定義する場合は、実世界のオブジェクトに対応する抽象テンプレートを作成します。テンプレートでは、アプリケーション環境でオブジェクトに必要な属性と動作を指定します。

12-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 381: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

図図図図 12-1 各アプリケーションでのオブジェクト属性のサブセットの使用各アプリケーションでのオブジェクト属性のサブセットの使用各アプリケーションでのオブジェクト属性のサブセットの使用各アプリケーションでのオブジェクト属性のサブセットの使用

属性がパブリック(クライアント・プログラムから参照可能)な場合でも、優れたプログラムでは、値を直接割り当てたり読み取るのではなく、指定したメソッドを介してのみデータを操作します。メソッドで追加チェックを実行できるため、データは適切な状態に保たれます。

実行時には、抽象型のインスタンスインスタンスインスタンスインスタンスが作成されます。これは、属性が設定された実オブジェクトです。

PL/SQL のオブジェクト型の使用 12-3

Page 382: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型を使用する理由

図図図図 12-2 オブジェクト型とそのオブジェクト(インスタンス)オブジェクト型とそのオブジェクト(インスタンス)オブジェクト型とそのオブジェクト(インスタンス)オブジェクト型とそのオブジェクト(インスタンス)

オブジェクト型を使用する理由オブジェクト型を使用する理由オブジェクト型を使用する理由オブジェクト型を使用する理由オブジェクト型によって、大規模なシステムが複数の論理エンティティに細分化されます。これによって、モジュール構造を持ち、複数のプロジェクトおよびチーム間で保持および再利用が可能なソフトウェア・コンポーネントを作成できます。

コードをデータに関連付けることで、オブジェクト型を使用してメンテナンスのためのコードを SQL スクリプトや PL/SQL ブロックではなく、メソッドに入れることができます。パラメータ値に基づいて異なる動作を実行する長いプロシージャを記述するのではなく、異なるオブジェクト型を定義して、少しずつ異なる操作を実行することができます。正しいオブジェクト型を宣言することで、その型の操作のみが実行されるようになります。

オブジェクト型を使用することによって、現実のデータをモデル化できます。複雑な実世界のエンティティと関連は、オブジェクト型に直接対応付けることができます。オブジェクト型は、Java や C++ などのオブジェクト指向言語で定義されたクラスに直接対応付けられます。

12-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 383: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構造

オブジェクト型の構造オブジェクト型の構造オブジェクト型の構造オブジェクト型の構造パッケージと同様に、オブジェクト型は仕様部と本体から構成されます(図 12-3 を参照)。仕様部仕様部仕様部仕様部はプログラムのインタフェースを定義し、データ操作に必要な演算(メソッド)とともに属性の集合を宣言します。本体本体本体本体は、メソッドのコードを定義します。

図図図図 12-3 オブジェクト型構造オブジェクト型構造オブジェクト型構造オブジェクト型構造

メソッドを使用するためにプログラムが必要とするすべての情報は、仕様部にあります。仕様部を変更しなくても、本体を変更できます。クライアント・プログラムには影響を与えません。

オブジェクト型の仕様部では、メソッドより前にすべての属性を宣言する必要があります。オブジェクト型の仕様部に属性の宣言しかない場合、オブジェクト型本体は不要です。本体では属性を宣言できません。オブジェクト型の仕様部のすべての宣言は、パブリック(オブジェクト型の外側から参照可能)です。

次の例では、実数部、虚数部および算術演算を持つ複素数のオブジェクト型を定義しています。

CREATE TYPE Complex AS OBJECT ( rpart REAL, -- "real" attribute ipart REAL, -- "imaginary" attribute MEMBER FUNCTION plus (x Complex) RETURN Complex, -- method MEMBER FUNCTION less (x Complex) RETURN Complex, MEMBER FUNCTION times (x Complex) RETURN Complex, MEMBER FUNCTION divby (x Complex) RETURN Complex);

CREATE TYPE BODY Complex AS MEMBER FUNCTION plus (x Complex) RETURN Complex IS BEGIN RETURN Complex(rpart + x.rpart, ipart + x.ipart); END plus;

MEMBER FUNCTION less (x Complex) RETURN Complex IS

PL/SQL のオブジェクト型の使用 12-5

Page 384: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

BEGIN RETURN Complex(rpart - x.rpart, ipart - x.ipart); END less;

MEMBER FUNCTION times (x Complex) RETURN Complex IS BEGIN RETURN Complex(rpart * x.rpart - ipart * x.ipart, rpart * x.ipart + ipart * x.rpart); END times;

MEMBER FUNCTION divby (x Complex) RETURN Complex IS z REAL := x.rpart**2 + x.ipart**2; BEGIN RETURN Complex((rpart * x.rpart + ipart * x.ipart) / z, (ipart * x.rpart - rpart * x.ipart) / z); END divby;END;/

オブジェクト型の構成要素オブジェクト型の構成要素オブジェクト型の構成要素オブジェクト型の構成要素オブジェクト型はデータと操作をカプセル化します。属性とメソッドはオブジェクト型仕様部で宣言できますが、定数、例外、カーソル、型は宣言できません。少なくとも 1 つの属性を宣言する必要があります( 大で 1000)。メソッドはオプションです。

属性属性属性属性

変数と同じように、属性は名前とデータ型を指定して宣言します。名前はそのオブジェクト型の中で一意である必要があります(他のオブジェクト型内では使用できます)。データ型には、任意の Oracle 型を使用できますが、次の型は使用できません。

� LONG、LONG RAW

� ROWID、UROWID

� PL/SQL 固有の型 BINARY_INTEGER(およびそのサブタイプ)、BOOLEAN、PLS_INTEGER、RECORD、REF CURSOR、%TYPE、%ROWTYPE

� PL/SQL パッケージ内で定義されている型

属性の宣言内では、代入演算子または DEFAULT句を使用しての属性の初期化はできません。また、属性に NOT NULL制約を課すことはできません。ただし、オブジェクトをデータベースの表に格納して、その表に制約を課すことはできます。

12-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 385: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

属性の集合によって形成されるデータ構造体の種類は、モデル化される実社会のオブジェクトに依存します。たとえば、分子と分母からなる有理数を表すために必要なのは、2 つのINTEGER変数のみです。一方、大学の学生を表すには、名前、住所、電話番号、状態などを入れるための複数の VARCHAR2変数、そしてコースおよび成績を入れるための 1 つのVARRAY変数が必要です。

データ構造体は非常に複雑なものとなることがあります。たとえば、属性のデータ型を別のオブジェクト型とすることができます(ネストされたネストされたネストされたネストされたオブジェクト型と呼ばれます)。それによって、より単純なオブジェクト型から複雑なオブジェクト型を作成することが可能になります。待ち行列、リスト、ツリーなどの一部のオブジェクト型は動的です。つまり、使用されるときに拡張します。自分自身への直接または間接の参照を含む再帰的オブジェクト型は、高度に洗練されたデータ・モデルを可能にします。

メソッドメソッドメソッドメソッド

一般にメソッドとは、オブジェクト型仕様部でキーワード MEMBERまたは STATICを使用して宣言されるサブプログラムです。メソッドの名前には、オブジェクト型またはその属性のいずれかと同じ名前は使用できません。次に示すように、MEMBERメソッドはインスタンスで起動されます。

instance_expression.method()

ただし、次に示すように、STATICメソッドはインスタンスではなくオブジェクト型で起動されます。

object_type_name.method()

パッケージ化されたサブプログラムと同様に、メソッドには仕様部と本体の 2 つの部分があります。仕様部仕様部仕様部仕様部は、メソッド名、オプションのパラメータ・リスト、およびファンクションの場合は戻り型から構成されます。本体本体本体本体は、特定の作業を実行するためのコードです。

オブジェクト型仕様部のメソッド仕様部ごとに、対応するメソッド本体がオブジェクト型本体に存在している必要があります。または、メソッドに NOT INSTANTIABLEを宣言し、メソッド本体がこの型のサブタイプにのみ存在することを示す必要があります。メソッドの仕様部と本体を一致させるために、PL/SQL コンパイラは、それらのヘッダーをトークンごとに比較します。ヘッダーは正確に一致する必要があります。

属性と同じように、仮パラメータは名前とデータ型を指定して宣言します。ただし、パラメータのデータ型をサイズ制約することはできません。データ型としては、任意の Oracle型を使用できますが、属性に認められていないものは使用できません。(12-6 ページの「属性」を参照。)同じ制限が戻り値の型にも適用されます。

PL/SQL のオブジェクト型の使用 12-7

Page 386: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

オブジェクト型のメソッドに使用できる言語オブジェクト型のメソッドに使用できる言語オブジェクト型のメソッドに使用できる言語オブジェクト型のメソッドに使用できる言語Oracle では、オブジェクトのメソッドを PL/SQL、Java または C 言語で実装できます。型でコール仕様部を指定すると、型のメソッドを Java または C 言語で実装できます。コール仕様部は、Oracle データ・ディクショナリ内の外部 C ファンクションまたは Java メソッドを発行します。これは、対応する SQL に名前、パラメータ型および戻り型をマップすることによって、ルーチンを発行します。Java コール仕様を作成する方法は、『Oracle Database Java 開発者ガイド』を参照してください。C コール仕様を作成する方法は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

オブジェクト型によるオブジェクト型によるオブジェクト型によるオブジェクト型による SELF パラメータの処理方法パラメータの処理方法パラメータの処理方法パラメータの処理方法MEMBERメソッドは SELFという名前の組込みパラメータを受け入れます。これはオブジェクト型のインスタンスです。SELFは常に MEMBERメソッドに渡される第 1 パラメータです。宣言しない場合は、自動的に宣言されます。

たとえば、transformメソッドは SELFを IN OUTパラメータとして宣言します。

CREATE TYPE Complex AS OBJECT ( MEMBER FUNCTION transform (SELF IN OUT Complex) ...

SELFには元のオブジェクトと同じデータ型を指定する必要があります。

MEMBERファンクションでは、SELFが宣言されていない場合、そのパラメータ・モードはデフォルトで INに設定されます。

MEMBERプロシージャでは、SELFが宣言されていない場合、そのパラメータ・モードはデフォルトで IN OUTに設定されます。

SELFには OUTパラメータ・モードを指定できません。

STATICメソッドは SELFの受入れや参照ができません。

メソッドの本体では、SELFはメソッドが起動されたオブジェクトを示します。SELF.attribute_nameまたは SELF.member_nameを参照すると、スーパータイプ内の何かではなく、そのオブジェクトを参照していることを明示できます。次の例で示されるように、メソッドでは修飾子なしで SELFの属性を参照できます。

CREATE FUNCTION gcd (x INTEGER, y INTEGER) RETURN INTEGER AS-- find greatest common divisor of x and y ans INTEGER;BEGIN IF (y <= x) AND (x MOD y = 0) THEN ans := y; ELSIF x < y THEN ans := gcd(y, x); ELSE ans := gcd(y, x MOD y); END IF; RETURN ans;END;

12-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 387: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

CREATE TYPE Rational AS OBJECT ( num INTEGER, den INTEGER, MEMBER PROCEDURE normalize, ...);

CREATE TYPE BODY Rational AS MEMBER PROCEDURE normalize IS g INTEGER; BEGIN g := gcd(SELF.num, SELF.den); g := gcd(num, den); -- equivalent to previous statement num := num / g; den := den / g; END normalize; ...END;

SQL 文からは、NULL インスタンス(SELFが NULL である状態)で MEMBERメソッドをコールすると、メソッドは起動されず NULL が戻されます。プロシージャ文からは、NULLインスタンスで MEMBERメソッドをコールすると、メソッドが起動される前に事前定義の例外 SELF_IS_NULLが呼び出されます。

オーバーロードオーバーロードオーバーロードオーバーロードパッケージ化されたサブプログラムと同じく、同じ種類(ファンクションまたはプロシージャ)のメソッドはオーバーロードできます。仮パラメータによってメソッドを区別できる場合、同じ名前を複数の異なるメソッドで使用できます。メソッドの 1 つをコールするとき、PL/SQL は実パラメータと仮パラメータのリストとを比較して、メソッドを検索します。

サブタイプも、スーパータイプから継承するメソッドをオーバーロードできます。この場合、メソッドの仮パラメータは正確に一致します。

2 つのメソッドの仮パラメータの違いがモードのみの場合、それらのメソッドはオーバーロードできません。戻り型しか違わない 2 つのメンバー関数はオーバーロードできません。詳細は、8-12 ページの「サブプログラム名のオーバーロード」を参照してください。

MAP メソッドとメソッドとメソッドとメソッドと ORDER メソッドメソッドメソッドメソッド

オブジェクト型のインスタンスには事前定義済の順序がありません。比較またはソートのためにそれらを順序付けるために、PL/SQL はユーザー提供の MAP メソッドメソッドメソッドメソッドをコールします。次の例で、キーワード MAPは、メソッド convert()が Rational型のオブジェクトを REAL値にマップすることによって順序付けることを示します。

PL/SQL のオブジェクト型の使用 12-9

Page 388: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

CREATE TYPE Rational AS OBJECT ( num INTEGER, den INTEGER, MAP MEMBER FUNCTION convert RETURN REAL,);

CREATE TYPE BODY Rational AS MAP MEMBER FUNCTION convert RETURN REAL IS BEGIN RETURN num / den; END convert;END;

PL/SQL は、マップ・メソッドを使用して、x > yなどのブール式を評価したり、DISTINCT、GROUP BYおよび ORDER BY句によって暗黙的に必要となる比較を実行します。MAPメソッド convert()は、すべての有理オブジェクトを順序付けする際の、オブジェクトの相対的な位置を戻します。

1 つのオブジェクト型に含めることができる MAPメソッドは 1 つのみです。組込みパラメータ SELFを受け入れて、スカラー型 DATE、NUMBER、VARCHAR2のうちの 1 つ、あるいはCHARACTERや REALなどの ANSI SQL 型を戻します。

あるいは、ORDER メソッドメソッドメソッドメソッドを使用することもできます。1 つのオブジェクト型に含めることができる ORDERメソッドは 1 つのみです。このメソッドは、戻り型が数値のファンクションである必要があります。次の例のキーワード ORDERは、メソッド match()によって、2 つのオブジェクトが比較されることを示しています。

CREATE TYPE Customer AS OBJECT ( id NUMBER, name VARCHAR2(20), addr VARCHAR2(30), ORDER MEMBER FUNCTION match (c Customer) RETURN INTEGER);

CREATE TYPE BODY Customer AS ORDER MEMBER FUNCTION match (c Customer) RETURN INTEGER IS BEGIN IF id < c.id THEN RETURN -1; -- any negative number will do ELSIF id > c.id THEN RETURN 1; -- any positive number will do ELSE RETURN 0; END IF; END;END;

12-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 389: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

各 ORDERメソッドは、組込みパラメータ SELFと、同じ型の別のオブジェクトの 2 つのパラメータを取ります。c1および c2が Customerオブジェクトの場合、c1 > c2などの比較操作を実行すると、自動的に match()がコールされます。このメソッドの戻り値は、負数、0(ゼロ)、または正数であり、SELFが他方のパラメータより小さい、等しい、あるいは大きいことを示しています。ORDERメソッドに渡されるパラメータのいずれかが NULLの場合、メソッドは NULL を戻します。

指針指針指針指針

MAPメソッドはハッシュ関数のような働きをし、オブジェクト値をスカラー値にマップし、<や =などの演算子を使用して比較します。ORDERメソッドは、単に 1 つのオブジェクト値をもう 1 つのオブジェクト値と比較します。

MAPメソッドまたは ORDERメソッドを宣言できますが、その両方は宣言できません。どちらかのメソッドを宣言すれば、オブジェクトを SQL 文およびプロシージャ文によって比較できます。どちらのメソッドも宣言しなければ、オブジェクトは SQL 文でのみ比較し、しかも比較できるのは等しいか等しくないかについてのみです。(同じ型の 2 つのオブジェクトが等しいとされるのは、それらの対応する属性の値が等しい場合のみです。)

大量のオブジェクトをソートまたはマージするときは、MAPメソッドを使用します。1 回のコールで、すべてのオブジェクトをスカラーにマップして、そのスカラーをソートできます。ORDERメソッドは、何回もコールする必要があるため効率が悪くなります(一度に 2 つのオブジェクトを比較することしかできません)。PL/SQL ではオブジェクト値に対してハッシュするため、ハッシュ結合のためには、MAPメソッドを使用する必要があります。

コンストラクタ・メソッドコンストラクタ・メソッドコンストラクタ・メソッドコンストラクタ・メソッド

どのオブジェクト型にもコンストラクタコンストラクタコンストラクタコンストラクタ・メソッドがあります。このコンストラクタ・メソッドは、そのオブジェクト型と同じ名前のファンクションで、そのオブジェクト型の新しいインスタンスを初期化して戻します。

Oracle では、すべてのオブジェクト型に対して、そのオブジェクト属性の順序、名前およびデータ型が一致する仮パラメータを使用して、デフォルトのコンストラクタが生成されます。

システム定義のコンストラクタをオーバーライドするか、または異なるシグネチャで新規ファンクションを定義して、ユーザー独自のコンストラクタ・メソッドを定義できます。

PL/SQL がコンストラクタを暗黙的にコールすることはありません。コンストラクタは明示的にコールする必要があります。

詳細は、12-18 ページの「オブジェクト・コンストラクタの定義」を参照してください。

PL/SQL のオブジェクト型の使用 12-11

Page 390: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の構成要素

既存のオブジェクト型の属性およびメソッドの変更(型の発展)既存のオブジェクト型の属性およびメソッドの変更(型の発展)既存のオブジェクト型の属性およびメソッドの変更(型の発展)既存のオブジェクト型の属性およびメソッドの変更(型の発展)ALTER TYPE文を使用すると、既存のオブジェクト型の属性の追加、変更または削除やメソッドの追加または削除ができます。

CREATE TYPE Person_typ AS OBJECT( name CHAR(20),ssn CHAR(12),address VARCHAR2(100));CREATE TYPE Person_nt IS TABLE OF Person_typ;CREATE TYPE dept_typ AS OBJECT( mgr Person_typ,emps Person_nt);CREATE TABLE dept OF dept_typ;

-- Add new attributes to Person_typ and propagate the change-- to Person_nt and dept_typALTER TYPE Person_typ ADD ATTRIBUTE (picture BLOB, dob DATE)CASCADE NOT INCLUDING TABLE DATA;

CREATE TYPE mytype AS OBJECT (attr1 NUMBER, attr2 NUMBER);ALTER TYPE mytype ADD ATTRIBUTE (attr3 NUMBER),DROP ATTRIBUTE attr2,ADD ATTRIBUTE attr4 NUMBER CASCADE;

プロシージャのコンパイル時には常に、参照先のオブジェクト型の現行バージョンが使用されます。サーバー上でオブジェクト型を参照している既存のプロシージャは、その型が変更されると無効になり、次回のコール時に自動的に再コンパイルされます。変更があった型を参照するクライアント側のプロシージャは、すべて手動で再コンパイルする必要があります。

スーパータイプからメソッドを削除すると、そのメソッドをオーバーライドするサブタイプにも変更が必要になる場合があります。サブタイプが影響を受けるかどうかは、ALTER TYPE文の CASCADEオプションを使用して検索できます。この文は、メソッドをオーバーライドするサブタイプがあるとロールバックされます。メソッドをスーパータイプから正常に削除するには、次の方法があります。

� 初にメソッドをサブタイプから永続的に削除します。

� サブタイプのメソッドを削除してから、後で OVERRIDINGキーワードを指定せずにALTER TYPE文を使用して追加します。

ALTER TYPE文の詳細は、『Oracle Database SQL リファレンス』を参照してください。アプリケーションに型の発展を使用する際の指針と、その型に依存する他の型およびデータを変更するためのオプションについては、『Oracle Database アプリケーション開発者ガイド -オブジェクト・リレーショナル機能』を参照してください。

12-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 391: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の定義

オブジェクト型の定義オブジェクト型の定義オブジェクト型の定義オブジェクト型の定義オブジェクト型は、任意の実社会のエンティティを表すことができます。たとえば、オブジェクト型によって、学生、銀行口座、コンピュータ・スクリーン、有理数、またはデータ構造体(待ち行列、スタック、リストなど)を表すことができます。ここでは、いくつかの完結した例を示して、オブジェクト型の設計の多くの面を示し、独自のオブジェクト型を作成する準備をします。

現在のところ、PL/SQL のブロック、サブプログラムまたはパッケージ内ではオブジェクト型を定義できません。SQL*Plus では、SQL 文 CREATE TYPEを使用して対話形式で定義できます。

PL/SQL の型の継承の概要の型の継承の概要の型の継承の概要の型の継承の概要PL/SQL では、単一継承モデルがサポートされます。オブジェクト型のサブタイプを定義できます。このサブタイプには、親の型(スーパータイプ)の属性とメソッドがすべて含まれます。また、サブタイプには他の属性やメソッドを含めたり、スーパータイプからのメソッドをオーバーライドできます。

サブタイプを特定の型から導出できるかどうかを定義できます。また、直接はインスタンス化できず、インスタンス化するサブタイプを宣言する必要がある型とメソッドも定義できます。

型のプロパティの一部は、ALTER TYPE文を使用して動的に変更できます。ALTER TYPE文を使用するか、またはスーパータイプを再定義してスーパータイプに変更を加えると、そのサブタイプには変更結果が自動的に反映されます。

TREAT演算子を使用すると、指定したサブタイプのオブジェクトのみを戻すことができます。

REFおよび DEREFファンクションからの値では、表またはビューの宣言された型、あるいはその 1 つ以上のサブタイプを表すことができます。

これらのオブジェクト・リレーショナル機能の詳細は、『Oracle Database アプリケーション開発者ガイド - オブジェクト・リレーショナル機能』を参照してください。

PL/SQL の型の継承の例の型の継承の例の型の継承の例の型の継承の例-- Create a supertype from which several subtypes will be derived.CREATE TYPE Person_typ AS OBJECT ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL;

-- Derive a subtype that has all the attributes of the supertype,-- plus some additional attributes.CREATE TYPE Student_typ UNDER Person_typ ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL;

-- Because Student_typ is declared NOT FINAL, you can derive

PL/SQL のオブジェクト型の使用 12-13

Page 392: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型の定義

-- further subtypes from it.CREATE TYPE PartTimeStudent_typ UNDER Student_typ( numhours NUMBER);

-- Derive another subtype. Because it has the default attribute-- FINAL, you cannot use Employee_typ as a supertype and derive-- subtypes from it.CREATE TYPE Employee_typ UNDER Person_typ( empid NUMBER, mgr VARCHAR2(30));

-- Define an object type that can be a supertype. Because the-- member function is FINAL, it cannot be overridden in any-- subtypes.

CREATE TYPE T AS OBJECT (..., MEMBER PROCEDURE Print(), FINAL MEMBERFUNCTION foo(x NUMBER)...) NOT FINAL;

-- We never want to create an object of this supertype. By using-- NOT INSTANTIABLE, we force all objects to use one of the subtypes-- instead, with specific implementations for the member functions.CREATE TYPE Address_typ AS OBJECT(...) NOT INSTANTIABLE NOT FINAL;

-- These subtypes can provide their own implementations of-- member functions, such as for validating phone numbers and-- postal codes. Because there is no "generic" way of doing these-- things, only objects of these subtypes can be instantiated.CREATE TYPE USAddress_typ UNDER Address_typ(...);CREATE TYPE IntlAddress_typ UNDER Address_typ(...);

-- Return REFs for those Person_typ objects that are instances of-- the Student_typ subtype, and NULL REFs otherwise.SELECT TREAT(REF(p) AS REF Student_typ) FROM Person_v p;

-- Example of using TREAT for assignment...

-- Return REFs for those Person_type objects that are instances of-- Employee_type or Student_typ, or any of their subtypes.SELECT REF(p) FROM Person_v P WHERE VALUE(p) IS OF (Employee_typ, Student_typ);

-- Similar to above, but do not allow any subtypes of Student_typ.SELECT REF(p) FROM Person_v p WHERE VALUE(p) IS OF(ONLY Student_typ);

-- The results of REF and DEREF can include objects of Person_typ-- and its subtypes such as Employee_typ and Student_typ.SELECT REF(p) FROM Person_v p;SELECT DEREF(REF(p)) FROM Person_v p;

12-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 393: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクトの宣言と初期化

オブジェクトの宣言と初期化オブジェクトの宣言と初期化オブジェクトの宣言と初期化オブジェクトの宣言と初期化オブジェクト型を宣言してスキーマにインストールすると、任意の PL/SQL ブロック、サブプログラムまたはパッケージの中で、それを使用してオブジェクトを宣言できます。たとえば、そのオブジェクト型を使用して属性、列、変数、バインド変数、レコード・フィールド、表要素、仮パラメータまたはファンクション結果のデータ型を指定できます。実行時には、そのオブジェクト型のインスタンスが作成されます。つまり、その型のオブジェクトがインスタンス化されます。オブジェクトごとに異なる値を保持できます。

そのようなオブジェクトは、通常の有効範囲規則とインスタンス化のルールに従います。ブロックまたはサブプログラムでは、ローカル・オブジェクトは、ブロックまたはサブプログラムに入ったときにインスタンス化され、ブロックまたはサブプログラムが終了した時点で消滅します。パッケージでは、そのパッケージが初めて参照された時点でオブジェクトのインスタンスが生成され、データベース・セッションが終わった時点で消滅します。

オブジェクトの宣言オブジェクトの宣言オブジェクトの宣言オブジェクトの宣言CHARや NUMBERなどの組込み型を使用できるところであれば、どこでもオブジェクト型を使用できます。次のブロックでは、Rational型のオブジェクト rを宣言しています。その後、オブジェクト型 Rationalのコンストラクタをコールして、そのオブジェクトを初期化します。このコールでは、属性 numおよび denにそれぞれ値 6 および 8 を代入しています。

DECLARE r Rational;BEGIN r := Rational(6, 8); dbms_output.put_line(r.num); -- prints 6

オブジェクトは、ファンクションおよびプロシージャの仮パラメータとして宣言できます。そのようにすると、オブジェクトをストアド・サブプログラムに渡したり、あるサブプログラムから別のサブプログラムに渡すことができます。次の例では、オブジェクト型Accountを使用して仮パラメータのデータ型を指定しています。

DECLARE ... PROCEDURE open_acct (new_acct IN OUT Account) IS ...

次の例では、オブジェクト型 Accountを使用してファンクションの戻り型を指定しています。

DECLARE ... FUNCTION get_acct (acct_id IN INTEGER) RETURN Account IS ...

PL/SQL のオブジェクト型の使用 12-15

Page 394: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクトの宣言と初期化

オブジェクトの初期化オブジェクトの初期化オブジェクトの初期化オブジェクトの初期化オブジェクト型のためのコンストラクタをコールしてそのオブジェクトを初期化するまで、そのオブジェクトは基本構造的に NULL になっています。つまり、その属性のみではなくオブジェクトそのものが NULL になっています。次の例を考えます。

DECLARE r Rational; -- r becomes atomically nullBEGIN r := Rational(2,3); -- r becomes 2/3

NULL のオブジェクトが別のオブジェクトと等しくなることは決してありません。実際のところ、NULL のオブジェクトを別のオブジェクトと比較すると、常に NULLになります。また、基本構造的に NULL になっているオブジェクトを他のオブジェクトに代入すると、そのオブジェクトも基本構造的に NULL になります(したがって再度初期化する必要があります)。同じように、次の例に示すように値のない NULLをオブジェクトに代入すると、そのオブジェクトは基本構造的に NULL になります。

DECLARE r Rational;BEGIN r Rational := Rational(1,2); -- r becomes 1/2 r := NULL; -- r becomes atomically null IF r IS NULL THEN ... -- condition yields TRUE

プログラミング上の習慣として、次の例に示すように、オブジェクトを宣言するときには初期化するようにしてください。

DECLARE r Rational := Rational(2,3); -- r becomes 2/3

PL/SQL による未初期化オブジェクトの処理による未初期化オブジェクトの処理による未初期化オブジェクトの処理による未初期化オブジェクトの処理式の中で、未初期化オブジェクトの属性は NULLとして評価されます。未初期化オブジェクトの属性に値を代入しようとすると、事前定義済の例外 ACCESS_INTO_NULLが呼び出されます。IS NULL比較演算子を未初期化オブジェクトまたはその属性に適用すると、結果はTRUEになります。

12-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 395: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト属性へのアクセス

次の例は、NULL のオブジェクトと、属性が NULL であるオブジェクトの違いを示しています。

DECLARE r Rational; -- r is atomically nullBEGIN IF r IS NULL THEN ... -- yields TRUE IF r.num IS NULL THEN ... -- yields TRUE r := Rational(NULL, NULL); -- initializes r r.num := 4; -- succeeds because r is no longer atomically null -- even though all its attributes are null r := NULL; -- r becomes atomically null again r.num := 4; -- raises ACCESS_INTO_NULLEXCEPTION WHEN ACCESS_INTO_NULL THEN ...END;

未初期化オブジェクトのメソッドのコールによって、事前定義済の例外NULL_SELF_DISPATCHが呼び出されます。未初期化オブジェクトの属性を INパラメータへの引数として渡すと、それは NULLと評価されます。OUTまたは IN OUTパラメータへの引数として渡されると、書き込むときに例外が呼び出されます。

オブジェクト属性へのアクセスオブジェクト属性へのアクセスオブジェクト属性へのアクセスオブジェクト属性へのアクセス属性は名前で参照します。属性にアクセスしたり、その値を変更するには、ドット表記法を使用します。

DECLARE r Rational := Rational(NULL, NULL); numerator INTEGER; denominator INTEGER;BEGIN denominator := r.den; -- Read value of attribute r.num := numerator; -- Assign value to attribute

属性名を連鎖させて、ネストされたオブジェクト型の属性にアクセスできます。たとえば、オブジェクト型の Addressおよび Studentを次のように定義するとします。

CREATE TYPE Address AS OBJECT ( street VARCHAR2(30), city VARCHAR2(20), state CHAR(2), zip_code VARCHAR2(5));

CREATE TYPE Student AS OBJECT (

PL/SQL のオブジェクト型の使用 12-17

Page 396: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト・コンストラクタの定義

name VARCHAR2(20), home_address Address, phone_number VARCHAR2(10), status VARCHAR2(10), advisor_name VARCHAR2(20), ...);

Address属性は zip_code属性を持つオブジェクト型です。sが Studentオブジェクトである場合、その zip_code属性には次のようにアクセスします。

s.home_address.zip_code

オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義オブジェクト・コンストラクタの定義デフォルトでは、オブジェクト型に対するコンストラクタの定義は不要です。システムによって、各属性に対応するパラメータを受け入れるデフォルト・コンストラクタが指定されます。

次のように、独自のコンストラクタを定義することもできます。

� 一部の属性にデフォルト値を指定する場合。コール元に頼らずに、すべての属性値に値が正しく供給されるようにできます。

� 多数の、オブジェクトの異なる部分を初期化するのみの、特殊目的のプロシージャを回避する場合。

� 新規属性を型へ追加する時に、コンストラクタをコールするアプリケーションでのコード変更を回避する場合。たとえば、属性は NULL に設定するが、コンストラクタへの既存のコールが継続して動作できるように、そのシグネチャは変更しない場合、コンストラクタには新しいコードが必要となります。

次に例を示します。

CREATE OR REPLACE TYPE rectangle AS OBJECT(-- The type has 3 attributes. length NUMBER, width NUMBER, area NUMBER,-- Define a constructor that has only 2 parameters. CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER) RETURN SELF AS RESULT);/

CREATE OR REPLACE TYPE BODY rectangle AS CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER) RETURN SELF AS RESULT

12-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 397: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト・コンストラクタのコール

AS BEGIN SELF.length := length; SELF.width := width;-- We compute the area rather than accepting it as a parameter. SELF.area := length * width; RETURN; END;END;/

DECLARE r1 rectangle; r2 rectangle;BEGIN-- We can still call the default constructor, with all 3 parameters. r1 := NEW rectangle(10,20,200);-- But it is more robust to call our constructor, which computes-- the AREA attribute. This guarantees that the initial value is OK. r2 := NEW rectangle(10,20);END;/

オブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコールオブジェクト・コンストラクタのコールコンストラクタは、ファンクション・コールが許可されているところでコールできます。次の例が示すように、すべてのファンクションと同じく、コンストラクタは式の一部としてコールされます。

DECLARE r1 Rational := Rational(2, 3); FUNCTION average (x Rational, y Rational) RETURN Rational IS BEGIN ... END;BEGIN r1 := average(Rational(3, 4), Rational(7, 11)); IF (Rational(5, 8) > r1) THEN ... END IF;END;

PL/SQL のオブジェクト型の使用 12-19

Page 398: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト・メソッドのコール

パラメータをコンストラクタに渡してコンストラクタをコールすると、インスタンスを生成するオブジェクトの属性に初期値が代入されます。すべての属性に値を入れるためにデフォルト・コンストラクタをコールする場合、属性には定数や変数とは異なりデフォルト値がないため、すべての属性にパラメータを指定する必要があります。次の例で示すように、n 番目のパラメータは n 番目の属性に値を代入します。

DECLARE r Rational;BEGIN r := Rational(5, 6); -- assign 5 to num, 6 to den -- now r is 5/6

次の例で示すように、位置表記法ではなく名前表記法を使用してコンストラクタをコールすることもできます。

BEGIN r := Rational(den => 6, num => 5); -- assign 5 to num, 6 to den

オブジェクト・メソッドのコールオブジェクト・メソッドのコールオブジェクト・メソッドのコールオブジェクト・メソッドのコールパッケージ化されたサブプログラムと同じく、メソッドはドット表記法を使用してコールされます。次の例では、属性 numおよび den(分子と分母)をそれらの 大公約数で割るメソッド normalize()をコールします。

DECLARE r Rational;BEGIN r := Rational(6, 8); r.normalize; dbms_output.put_line(r.num); -- prints 3END;

次の例でわかるように、メソッドのコールは連鎖させることができます。実行は左から右へと進んでいきます。 初にメンバー関数 reciprocal()がコールされ、次にメンバー・プロシージャ normalize()がコールされます。

DECLARE r Rational := Rational(6, 8);BEGIN r.reciprocal().normalize; dbms_output.put_line(r.num); -- prints 4END;

SQL 文からパラメータのないメソッドをコールするには、空のパラメータ・リストが必要です。プロシージャ文では、コールを連鎖しないかぎり空のパラメータ・リストは必要ありません。連鎖する場合は、 後のコール以外のすべてのコールで空のパラメータ・リストが必要です。

12-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 399: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

REF 修飾子によるオブジェクトの共有

プロシージャは式の一部としてではなく文としてコールされため、追加のメソッド・コールをプロシージャの右側に連鎖させることはできません。たとえば、次の宣言は誤りです。

r.normalize().reciprocal; -- not allowed

さらに、2 つのファンクション・コールの連鎖では、1 番目のファンクションは 2 番目のファンクションに渡せるオブジェクトを戻す必要があります。

静的メソッドの場合、コールでは型のインスタンスを指定するかわりに、表記法type_name.method_nameを使用します。

サブタイプのインスタンスを使用してメソッドをコールする場合、実際に実行されるメソッドは型の継承での宣言によって決まります。サブタイプがスーパータイプから継承するメソッドをオーバーライドする場合、コールではサブタイプの実装が使用されます。また、サブタイプがメソッドをオーバーライドしない場合、コールではスーパータイプの実装が使用されます。この機能は動的メソッド・ディスパッチと呼ばれます。

REF 修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有修飾子によるオブジェクトの共有大きいオブジェクトのコピーをサブプログラム間で受渡しするのは非効率的です。かわりに、ポインタを渡す方が便利です。ref は、オブジェクトへのポインタです。

共有を使用すると、データの不要なレプリケートが行われません。共有されているオブジェクトが更新されるとき、変更は 1 箇所のみで行われ、すべての ref では更新された値をすぐに取り出せます。

CREATE TYPE Home AS OBJECT ( address VARCHAR2(35), owner VARCHAR2(25), age INTEGER, style VARCHAR(15), floor plan BLOB, price REAL(9,2), ...);/CREATE TABLE homes OF Home;

オブジェクト型 Personを訂正することで、複数の人が同じ家を共有する家族をモデル化できます。オブジェクトへのポインタを含む ref を宣言するために、型修飾子 REFを使用します。

CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(10), last_name VARCHAR2(15), birthday DATE, home_address REF Home, -- can be shared by family phone_number VARCHAR2(15),

PL/SQL のオブジェクト型の使用 12-21

Page 400: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

REF 修飾子によるオブジェクトの共有

ss_number INTEGER, mother REF Person, -- family members refer to each other father REF Person, ...);

人から家への参照および人と人の間の参照によって、実社会に存在する関係をモデル化しているところに注目してください。

ref は、変数、パラメータ、フィールド、または属性として宣言できます。ref は SQL のDML 文の中で入力変数または出力変数として使用できます。

ref を通してナビゲートできません。つまり、x.attributeなどの式に対して(xは ref)、PL/SQL は参照されるオブジェクトが格納されている表にナビゲートできません。たとえば、次の割当ては誤りです。

DECLARE p_ref REF Person; phone_no VARCHAR2(15); BEGIN phone_no := p_ref.phone_number; -- not allowed

オブジェクトにアクセスするにはファンクション DEREFを使用するか、パッケージUTL_REFをコールする必要があります。例については、12-26 ページの「ファンクションDEREF の使用」を参照してください。

先送り型定義先送り型定義先送り型定義先送り型定義参照できるスキーマ・オブジェクトは、すでに存在するもののみです。次の例の 初のCREATE TYPE文は、まだ存在していないオブジェクト型 Departmentを参照しているため、誤りです。

CREATE TYPE Employee AS OBJECT ( name VARCHAR2(20), dept REF Department, -- not allowed ...);

CREATE TYPE Department AS OBJECT ( number INTEGER, manager Employee, ...);

12-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 401: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

CREATE TYPE文の順番を入れ替えても意味がありません。これは、オブジェクト型が相互相互相互相互に依存に依存に依存に依存しているためです。オブジェクト型 Employeeは、オブジェクト型 Departmentを参照する属性を持ち、オブジェクト型 Departmentは型 Employeeの属性を持ちます。この問題を解決するには、相互に依存するオブジェクト型の定義が可能な、先送り型定義と呼ばれる特別な CREATE TYPE文を使用します。

上の例をデバッグするには、その前に次の文を追加してください。

CREATE TYPE Department; -- forward type definition -- at this point, Department is an incomplete object type

先送り型定義によって作成されたオブジェクト型は、(完全に定義されるまで)属性またはメソッドがないため、不完全なオブジェクト型不完全なオブジェクト型不完全なオブジェクト型不完全なオブジェクト型と呼ばれます。

純粋ではない純粋ではない純粋ではない純粋ではない不完全なオブジェクト型は、属性は持っていますがコンパイルするとエラーが発生します。これは、そのオブジェクト型が未定義の型を参照しているためです。たとえば、次の CREATE TYPE文は、オブジェクト型 Addressが未定義なためにエラーを引き起こします。

CREATE TYPE Customer AS OBJECT ( id NUMBER, name VARCHAR2(20), addr Address, -- not yet defined phone VARCHAR2(15));

先送り型定義によって、オブジェクト型 Addressの定義を遅らせることができます。不完全な型 Customerを他のアプリケーション開発者は ref で使用できます。

SQL を使用したオブジェクトの操作を使用したオブジェクトの操作を使用したオブジェクトの操作を使用したオブジェクトの操作列のデータ型を指定するには、CREATE TABLE文の中でオブジェクト型を使用します。表の作成後は、SQL 文を使用してオブジェクトの挿入、属性の選択、メソッドのコールおよび状態の更新ができます。

注意注意注意注意 : リモート・オブジェクトまたは分散オブジェクトへはアクセスできません。

次の SQL*Plus スクリプトで、INSERT文はオブジェクト型 Rationalのコンストラクタをコールし、結果として生成されたオブジェクトを挿入(INSERT)します。SELECT文は属性 numの値を取り出します。UPDATE文はメンバー・メソッド reciprocal()をコールします。これは、属性 numと denを交換した後、Rationalの値を戻します。属性やメソッドを参照するには、表の別名が必要であることに注意してください。(詳細は、付録 D を参照。)

CREATE TABLE numbers (rn Rational, ...)/INSERT INTO numbers (rn) VALUES (Rational(3, 62)) -- inserts 3/62/

PL/SQL のオブジェクト型の使用 12-23

Page 402: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

SELECT n.rn.num INTO my_num FROM numbers n ... -- returns 3/UPDATE numbers n SET n.rn = n.rn.reciprocal() ... -- yields 62/3

この方法でオブジェクトをインスタンス化するとき、それはデータベースの表の外部では認識されません。ただし、そのオブジェクト型はどの表からも独立して存在していて、他の方法でオブジェクトを作成するために使用できます。

次の例では、Rational型のオブジェクトを行に格納する表を作成します。オブジェクトの行を含むそのような表は、オブジェクト表オブジェクト表オブジェクト表オブジェクト表と呼ばれます。行の各列は、そのオブジェクト型の属性に対応します。行ごとに異なる列の値を持つことが可能です。

CREATE TABLE rational_nums OF Rational;

オブジェクト表の各行ごとにオブジェクト識別子オブジェクト識別子オブジェクト識別子オブジェクト識別子があります。オブジェクト識別子は、その行に格納されているオブジェクトを一意に識別して、そのオブジェクトへの参照として機能します。

オブジェクトの選択オブジェクトの選択オブジェクトの選択オブジェクトの選択オブジェクト型 Personとオブジェクト表 personsを作成する次の SQL*Plus スクリプトを実行して、その表にデータを入れたとします。

CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(15), last_name VARCHAR2(15), birthday DATE, home_address Address, phone_number VARCHAR2(15))/CREATE TABLE persons OF Person/

次の副問合せは、Personオブジェクトの属性しか含まない行からなる結果セットを生成します。

BEGIN INSERT INTO employees -- another object table of type Person SELECT * FROM persons p WHERE p.last_name LIKE '%Smith';

オブジェクトの結果セットを戻すには、次の項で説明するファンクション VALUEを使用する必要があります。

12-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 403: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

ファンクションファンクションファンクションファンクション VALUE の使用の使用の使用の使用その名前のとおり、ファンクション VALUEはオブジェクトの値を戻します。VALUEは相関変数を引数とします。(この文脈で相関変数とは、オブジェクト表の行に対応付けられている行変数または表別名のことです。)たとえば、Personオブジェクトから結果セットを戻すには、VALUEを次のように使用します。

BEGIN INSERT INTO employees SELECT VALUE(p) FROM persons p WHERE p.last_name LIKE '%Smith';

次の例では、VALUEを使用して特定の Personオブジェクトを戻しています。

DECLARE p1 Person; p2 Person; ...BEGIN SELECT VALUE(p) INTO p1 FROM persons p WHERE p.last_name = 'Kroll'; p2 := p1; ...END;

この時点で、p1は姓が 'Kroll'のストアド・オブジェクトのコピーであるローカルPersonオブジェクト、p2は p1のコピーである別のローカル Personオブジェクトです。次の例に示すように、これらの変数を使用して、それらに含まれるオブジェクトにアクセスしたり更新できます。

BEGIN p1.last_name := p1.last_name || ' Jr';

この時点で、ローカル Personオブジェクトである p1は、姓が 'Kroll Jr'になっています。

ファンクションファンクションファンクションファンクション REF の使用の使用の使用の使用ファンクション REFを使用すると、ref を取り出せます。このファンクションは、VALUEと同様に相関変数を引数とします。次の例では、Personオブジェクトへの 1 つまたは複数のref を取り出し、その ref を表 person_refsに挿入します。

BEGIN INSERT INTO person_refs SELECT REF(p) FROM persons p WHERE p.last_name LIKE '%Smith';

PL/SQL のオブジェクト型の使用 12-25

Page 404: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

次の例では、ref と属性を同時に取り出します。

DECLARE p_ref REF Person; taxpayer_id VARCHAR2(9);BEGIN SELECT REF(p), p.ss_number INTO p_ref, taxpayer_id FROM persons p WHERE p.last_name = 'Parker'; -- must return one rowEND;

この例では、Personオブジェクトの属性を更新します。

DECLARE p_ref REF Person; my_last_name VARCHAR2(15);BEGIN SELECT REF(p) INTO p_ref FROM persons p WHERE p.last_name = my_last_name; UPDATE persons p SET p = Person('Jill', 'Anders', '11-NOV-67', ...) WHERE REF(p) = p_ref;END;

参照先がない参照先がない参照先がない参照先がない REF のテストのテストのテストのテストref が指すオブジェクトが削除されると、その ref は、存在しないオブジェクトを指す、参照参照参照参照先がない先がない先がない先がない REF として残ります。この状態になっているかどうかをテストするには、SQL 述語の IS DANGLINGを使用します。たとえば、departmentというリレーショナル表のmanagerという列に、あるオブジェクト表に格納されている Employeeというオブジェクトへの ref があるとします。次の UPDATE文を使用すると、参照先がない REF を NULL に変換できます。

UPDATE department SET manager = NULL WHERE manager IS DANGLING;

ファンクションファンクションファンクションファンクション DEREF の使用の使用の使用の使用PL/SQL プロシージャ文の中では、ref を通してナビゲートできません。SQL 文の中でファンクション DEREFを使用して、ポインタを参照解除し、ポインタが指す値を取得する必要があります。DEREFはオブジェクトへの参照を引数とし、そのオブジェクトの値を戻します。参照先にオブジェクトが存在しなければ、DEREFは NULL オブジェクトを戻します。

12-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 405: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

次の例では、Personオブジェクトへの ref を参照解除します。ダミーの表 DUALから選択を実行できます。これは、オブジェクト表に格納されているオブジェクトがすべて、一意のオブジェクト識別子を持っていて、その識別子は、オブジェクトへの ref の一部となっているためです。

DECLARE p1 Person; p_ref REF Person; name VARCHAR2(15);BEGIN /* Assume that p_ref holds a valid reference to an object stored in an object table. */ SELECT DEREF(p_ref) INTO p1 FROM dual; name := p1.last_name;

次のように、連続するいくつかの SQL 文の中で DEREFを使用して ref を参照解除できます。

CREATE TYPE PersonRef AS OBJECT (p_ref REF Person)/DECLARE name VARCHAR2(15); pr_ref REF PersonRef; pr PersonRef; p Person;BEGIN /* Assume pr_ref holds a valid reference. */ SELECT DEREF(pr_ref) INTO pr FROM dual; SELECT DEREF(pr.p_ref) INTO p FROM dual; name := p.last_name;END/次の例に示すように、ファンクション DEREFをプロシージャ文の中で使用することはできません。

BEGIN p1 := DEREF(p_ref); -- not allowed

SQL 文の中では、ドット表記法を使用してオブジェクト列の ref 属性までナビゲートしたり、ある ref 属性から他の ref 属性にナビゲートできます。また、表の別名を使用して、ref列から属性にナビゲートできます。たとえば、次の構文は有効です。

table_alias.object_column.ref_attributetable_alias.object_column.ref_attribute.attributetable_alias.ref_column.attribute

PL/SQL のオブジェクト型の使用 12-27

Page 406: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

オブジェクト型 Addressと Person、およびオブジェクト表 personsを作成する次のSQL*Plus スクリプトを実行したとします。

CREATE TYPE Address AS OBJECT ( street VARCHAR2(35), city VARCHAR2(15), state CHAR(2), zip_code INTEGER)/CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(15), last_name VARCHAR2(15), birthday DATE, home_address REF Address, -- shared with other Person objects phone_number VARCHAR2(15))/CREATE TABLE persons OF Person/

ref 属性 home_addressは、オブジェクト表 personsの列に対応しています。home_addressは、他の表に格納されているオブジェクト Addressへの ref です。表の内容を入力した後に、次のように ref を参照解除することで特定のアドレスを選択できます。

DECLARE addr1 Address, addr2 Address,BEGIN SELECT DEREF(home_address) INTO addr1 FROM persons p WHERE p.last_name = 'Derringer';

次の例では、ref 列 home_addressから属性 streetにナビゲートします。この場合、表の別名が必要です。

DECLARE my_street VARCHAR2(25),BEGIN SELECT p.home_address.street INTO my_street FROM persons p WHERE p.last_name = 'Lucas';

オブジェクトの挿入オブジェクトの挿入オブジェクトの挿入オブジェクトの挿入オブジェクトをオブジェクト表に追加するには、INSERT文を使用します。次の例では、Personオブジェクトをオブジェクト表 personsに挿入します。

BEGIN INSERT INTO persons VALUES ('Jenifer', 'Lapidus', ...);

12-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 407: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

または、オブジェクト型 Personのコンストラクタを使用してもオブジェクトをオブジェクト表 personsに追加できます。

BEGIN INSERT INTO persons VALUES (Person('Albert', 'Brooker', ...));

次の例では、RETURNING句を使用して Personの ref をローカル変数に格納します。この句が、SELECT文でどのように解釈されるかに注意してください。RETURNING句は、UPDATE文と DELETE文でも使用できます。

DECLARE p1_ref REF Person; p2_ref REF Person;BEGIN INSERT INTO persons p VALUES (Person('Paul', 'Chang', ...)) RETURNING REF(p) INTO p1_ref; INSERT INTO persons p VALUES (Person('Ana', 'Thorne', ...)) RETURNING REF(p) INTO p2_ref;

オブジェクトをオブジェクト表に挿入するには、同じ型のオブジェクトを戻す副問合せを使用します。次に例を示します。

BEGIN INSERT INTO persons2 SELECT VALUE(p) FROM persons p WHERE p.last_name LIKE '%Jones';

オブジェクト表 persons2にコピーされた行に、新しいオブジェクト識別子が付けられます。オブジェクト識別子はオブジェクト表 personsからはコピーされません。

次のスクリプトは、Person型の列を持つ departmentというリレーショナル表を作成してから、その表に行を挿入します。コンストラクタ Person()によって、列 managerに値が与えられます。

CREATE TABLE department ( dept_name VARCHAR2(20), manager Person, location VARCHAR2(20))/INSERT INTO department VALUES ('Payroll', Person('Alan', 'Tsai', ...), 'Los Angeles')/

列 managerに格納される新しい Personオブジェクトは、行ではなく列に格納されるため、オブジェクト識別子はなく、参照はできません。

PL/SQL のオブジェクト型の使用 12-29

Page 408: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL を使用したオブジェクトの操作

オブジェクトの更新オブジェクトの更新オブジェクトの更新オブジェクトの更新次の例に示すように、オブジェクト表内のオブジェクトの属性を変更するには、UPDATE文を使用します。

BEGIN UPDATE persons p SET p.home_address = '341 Oakdene Ave' WHERE p.last_name = 'Brody'; UPDATE persons p SET p = Person('Beth', 'Steinberg', ...) WHERE p.last_name = 'Steinway'; END;

オブジェクトの削除オブジェクトの削除オブジェクトの削除オブジェクトの削除オブジェクト(行)をオブジェクト表から削除するには、DELETE文を使用します。オブジェクトを選択的に削除するには、次のように、WHERE句を使用します。

BEGIN DELETE FROM persons p WHERE p.home_address = '108 Palm Dr';END;

12-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 409: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の

13

PL/SQL の言語要素の言語要素の言語要素の言語要素

この章は、PL/SQL 構文および方法のクイック・リファレンス・ガイドです。コマンド、パラメータおよびその他の言語要素を組み合せて PL/SQL 文を作成する方法を示します。また、使用上の注意および簡単な例も示します。

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

� 代入文

� AUTONOMOUS_TRANSACTION プラグマ

� ブロック

� CASE 文

� CLOSE 文

� コレクション・メソッド

� コレクション

� コメント

� COMMIT 文

� 定数と変数

� カーソル属性

� カーソル変数

� カーソル

� DELETE 文

� EXCEPTION_INIT プラグマ

� 例外

� EXECUTE IMMEDIATE 文

言語要素 13-1

Page 410: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� EXIT 文

� 式

� FETCH 文

� FORALL 文

� ファンクション

� GOTO 文

� IF 文

� INSERT 文

� リテラル

� LOCK TABLE 文

� LOOP 文

� MERGE 文

� NULL 文

� オブジェクト型

� OPEN 文

� OPEN-FOR 文

� OPEN-FOR-USING 文

� パッケージ

� プロシージャ

� RAISE 文

� レコード

� RESTRICT_REFERENCES プラグマ

� RETURN 文

� ROLLBACK 文

� %ROWTYPE 属性

� SAVEPOINT 文

� SCN_TO_TIMESTAMP ファンクション

� SELECT INTO 文

� SERIALLY_REUSABLE プラグマ

13-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 411: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

� SET TRANSACTION 文

� SQL カーソル

� SQLCODE ファンクション

� SQLERRM ファンクション

� TIMESTAMP_TO_SCN ファンクション

� %TYPE 属性

� UPDATE 文

PL/SQL の言語要素 13-3

Page 412: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

代入文

代入文代入文代入文代入文

代入文は、変数、フィールド、パラメータまたは要素の現在の値を設定します。代入文は、代入のターゲットと、それに続く代入演算子および式で構成されています。代入文を実行すると、式が評価され、結果の値がターゲットに格納されます。詳細は、2-22 ページの「変数への値の代入」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

attribute_nameオブジェクト型の属性を指定します。名前はそのオブジェクト型の中で一意である必要があります(他のオブジェクト型内では使用できます)。属性の宣言内では、代入演算子またはDEFAULT句を使用しての属性の初期化はできません。また、属性に NOT NULL制約を課すことはできません。

collection_name現行の有効範囲のうち、これより前の部分で宣言されているネストした表、索引付き表または VARRAY を指定します。

collection_name( index )

cursor_variable_name

: host_cursor_variable_name

: host_variable_name: indicator_name

object_name. attribute_name

parameter_name

record_name. field_name

variable_name

:= expression ;

assignment_statement

13-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 413: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

代入文

cursor_variable_name現行の有効範囲の中で事前に宣言されている PL/SQL カーソル変数を識別します。カーソル変数に代入できるのは、別のカーソル変数の値のみです。

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。expressionの構文は、13-71 ページの「式」を参照してください。代入文を実行すると、式が評価され、結果の値が代入のターゲットに格納されます。値とターゲットのデータ型には互換性が必要です。

field_nameユーザー定義のレコードまたは %ROWTYPEレコード内のフィールドを指定します。

host_cursor_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

host_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡される変数を識別します。ホスト変数には、接頭辞としてコロンを付けてください。

index戻される値が BINARY_INTEGER型の値、またはその型に暗黙的に変換可能な値になる数値式です。

indicator_namePL/SQL ホスト環境で宣言され、PL/SQL に渡される標識変数を識別します。標識変数には、接頭辞としてコロンを付ける必要があります。標識変数は、関連付けられたホスト変数の値または条件を示します。たとえば、Oracle プリコンパイラ環境では、標識変数を使用して出力ホスト変数内の NULL や切り捨てられた値を検出できます。

object_name現行の有効範囲のうち、これより前の部分で宣言されているオブジェクト型のインスタンスを識別します。

parameter_name代入文が使用されているサブプログラムの仮パラメータ OUTまたは IN OUTを識別します。

PL/SQL の言語要素 13-5

Page 414: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

代入文

record_name現行の有効範囲のうち、これより前に宣言されているユーザー定義のレコードまたは%ROWTYPEレコードです。

variable_name現行の有効範囲の中で事前に宣言されている PL/SQL 変数を識別します。

使用上の注意使用上の注意使用上の注意使用上の注意

デフォルトでは、宣言で初期化されていない変数は、ブロックまたはサブプログラムに入るたびに NULLに初期化されます。変数を式の中で使用する前に、その変数に値を代入する必要があります。

NOT NULLと定義されている変数には NULL を代入できません。NULL を代入しようとすると、PL/SQL は事前定義の例外 VALUE_ERRORを呼び出します。

ブール変数に代入できるのは、値 TRUE、FALSEおよび NULLのみです。

比較またはその他のテスト結果をブール変数に代入できます。

式の値をレコード内の特定のフィールドに代入できます。

レコード内のすべてのフィールドに一度に値を代入できます。PL/SQL では、レコードの宣言で同じカーソルまたは表が参照されている場合は、レコード全体の間での集計代入ができます。次の例では、レコード内のすべてのフィールドの値を別のレコードにコピーします。

DECLARE emp_rec1 emp%ROWTYPE; emp_rec2 emp%ROWTYPE; dept_rec dept%ROWTYPE;BEGIN ... emp_rec1 := emp_rec2;

コレクション名に添字を付けると、式の値をコレクションの特定の要素に代入できます。

13-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 415: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

代入文

例例例例DECLARE wages NUMBER; hours_worked NUMBER; hourly_salary NUMBER; bonus NUMBER; country VARCHAR2(128); counter NUMBER := 0; done BOOLEAN; emp_rec 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); emp_rec.first_name := 'Antonio'; comm_tab(5) := 20000 * 0.15;END;/

関連項目関連項目関連項目関連項目

定数と変数、式、SELECT INTO 文

PL/SQL の言語要素 13-7

Page 416: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

AUTONOMOUS_TRANSACTION プラグマ

AUTONOMOUS_TRANSACTION プラグマプラグマプラグマプラグマ

AUTONOMOUS_TRANSACTIONプラグマは、トランザクション内のサブプログラムの動作方法を変更します。このプラグマでマークされたサブプログラムは、メイン・トランザクションでデータをコミットまたはロールバックすることなく、実行した SQL 操作をコミットまたはロールバックできます。詳細は、6-45 ページの「自律型トランザクションによる独立した作業単位の実行」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

PRAGMA文がプラグマ(コンパイラ・ディレクティブ)であることを表します。プラグマは、実行時ではなくコンパイル時に処理されます。プラグマは、コンパイラに情報を渡します。

使用上の注意使用上の注意使用上の注意使用上の注意

このプラグマは次のものに適用できます。

� トップレベル(ネストしていない)の無名 PL/SQL ブロック

� ローカル、スタンドアロンおよびパッケージのファンクションとプロシージャ

� SQL オブジェクト型のメソッド

� データベース・トリガー

このプラグマは、パッケージ全体またはオブジェクト型全体には適用できません。かわりに、各パッケージ・サブプログラムまたはオブジェクト・メソッドに適用できます。

プラグマは、宣言部の任意の場所でコーディングできます。見やすくするために、セクションの先頭にプラグマをコーディングしてください。

自律型トランザクションは、開始すると完全に独立します。ロック、リソースまたはコミット依存関係をメイン・トランザクションと共有することはありません。メイン・トランザクションがロールバックする場合でも、イベントや増分再試行カウンタなどのログを取ることができます。

PRAGMA AUTONOMOUS_TRANSACTION ;

autonomous_transaction_pragma

13-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 417: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

AUTONOMOUS_TRANSACTION プラグマ

通常のトリガーとは異なり、自律型トリガーには、COMMIT、ROLLBACKなどのトランザクション制御文を含めることができます。また、EXECUTE IMMEDIATE文を使用して DDL 文

(CREATE、DROPなど)を発行できます。

自律型トランザクションによって行われた変更は、自律型トランザクションがコミットすると、他のトランザクションから参照できるようになります。変更は、メイン・トランザクションが再開するとメイン・トランザクションからも参照できるようになりますが、これは分離レベルが READ COMMITTED(デフォルト)に設定されている場合のみです。メイン・トランザクションの分離レベルを SERIALIZABLEに設定すると、その自律型トランザクションによって行われた変更は、メイン・トランザクションが再開してもメイン・トランザクションからは参照できません。

メイン・トランザクション内で、自律型サブプログラムをコールする前にマークされたセーブポイントまでロールバックしても、自律型トランザクションはロールバックされません。自律型トランザクションは、メイン・トランザクションからは完全に独立していることに注意してください。

メイン・トランザクション(自律型ルーチンの終了まで再開できない)が保持するリソースに、自律型トランザクションがアクセスしようとすると、デッドロックが発生します。この場合、Oracle は自律型トランザクションで例外を呼び出します。例外が未処理になった場合、自律型トランザクションはロールバックされます。

コミットまたはロールバックせずにアクティブな自律型トランザクションを終了しようとすると、Oracle は例外を呼び出します。例外が未処理になった場合、またはその他の未処理例外が発生してトランザクションが終了した場合、トランザクションはロールバックされます。

例例例例

次の例では、パッケージ・ファンクションを自律型としてマークします。

CREATE PACKAGE banking AS FUNCTION balance (acct_id INTEGER) RETURN REAL;END banking;/

CREATE PACKAGE BODY banking AS FUNCTION balance (acct_id INTEGER) RETURN REAL IS PRAGMA AUTONOMOUS_TRANSACTION; my_bal REAL; BEGIN NULL; END;END banking;/

DROP PACKAGE banking;

PL/SQL の言語要素 13-9

Page 418: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

AUTONOMOUS_TRANSACTION プラグマ

次の例では、トリガーでトランザクション制御文を発行します。

CREATE TABLE anniversaries AS SELECT DISTINCT TRUNC(hire_date) anniversary FROM employees;ALTER TABLE anniversaries ADD PRIMARY KEY (anniversary);

CREATE TRIGGER anniversary_trigger BEFORE INSERT ON employees FOR EACH ROWDECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN INSERT INTO anniversaries VALUES(TRUNC(:new.hire_date));-- Only commits the preceding INSERT, not the INSERT that fired-- the trigger. COMMIT; EXCEPTION-- If someone else was hired on the same day, we get an exception-- because of duplicate values. That's OK, no action needed. WHEN OTHERS THEN NULL;END;/

DROP TRIGGER anniversary_trigger;DROP TABLE anniversaries;

関連項目関連項目関連項目関連項目

EXCEPTION_INIT プラグマ、RESTRICT_REFERENCES プラグマ、SERIALLY_REUSABLEプラグマ

13-10 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 419: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

ブロックブロックブロックブロック

PL/SQL におけるプログラムの基本単位はブロックです。PL/SQL ブロックは、キーワードDECLARE、BEGIN、EXCEPTIONおよび ENDで定義します。これらのキーワードは、ブロックを宣言部、実行部、例外処理部に分けます。このうち必ず存在する必要があるのは実行部のみです。ブロックの中では、実行可能文を置ける場所ならば別のブロックをネストできます。詳細は、1-6 ページの「ブロック構造」および 2-19 ページの「PL/SQL の識別子の有効範囲と可視性」を参照してください。

構文構文構文構文

<< label_name >> DECLARE

plsql_block

BEGIN statement

EXCEPTION exception_handlerEND

label_name;

record_type_definition

ref_cursor_type_definition

table_type_definition

subtype_definition

varray_type_definition

type_definition

type_definition

item_declaration

function_declaration

procedure_declaration

SUBTYPE subtype_name IS base_type( constraint ) NOT NULL

;

subtype_definition

PL/SQL の言語要素 13-11

Page 420: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

collection_declaration

constant_declaration

cursor_declaration

cursor_variable_declaration

exception_declaration

object_declaration

object_ref_declaration

record_declaration

variable_declaration

item_declaration

commit_statement

delete_statement

insert_statement

lock_table_statement

rollback_statement

savepoint_statement

select_statement

set_transaction_statement

update_statement

sql_statement

13-12 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 421: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

base_type任意のスカラーまたは CHAR、DATE、RECORDなどのユーザー定義の PL/SQL データ型指定子です。

BEGINPL/SQL ブロックの実行部の開始を示すキーワードです。実行部には実行可能文が置かれます。PL/SQL ブロックには 1 つ以上の実行可能文(NULL文でも可)が含まれている必要があります。

<< label_name >>

assignment_statement

close_statement

execute_immediate_statement

exit_statement

fetch_statement

forall_statement

goto_statement

if_statement

loop_statement

null_statement

open_statement

open_for_statement

plsql_block

raise_statement

return_statement

sql_statement

statement

PL/SQL の言語要素 13-13

Page 422: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

collection_declarationコレクションを宣言します(索引付き表、ネストした表または VARRAY)。collection_declarationの構文は、13-29 ページの「コレクション」を参照してください。

constant_declaration定数を宣言します。constant_declarationの構文は、13-39 ページの「定数と変数」を参照してください。

constraintCHARや NUMBERなどの制約できるデータ型にのみ適用されます。文字データ型の場合は、大サイズのバイト数を指定します。数値データ型の場合は、精度と位取りの 大値を指定

します。

cursor_declaration明示カーソルを宣言します。cursor_declarationの構文は、13-53 ページの「カーソル」を参照してください。

cursor_variable_declarationカーソル変数を宣言します。cursor_variable_declarationの構文は、13-47 ページの

「カーソル変数」を参照してください。

DECLAREPL/SQL ブロックの宣言部の開始を示すキーワードです。宣言部にはローカル宣言が置かれます。ローカルに宣言された項目は現行のブロックとそのすべてのサブブロックにのみ存在し、外側のブロックからは見えません。PL/SQL ブロックの宣言部はオプションです。宣言部は、ブロックの実行部の開始を示すキーワード BEGINによって暗黙的に終了します。

PL/SQL では前方参照ができません。他の文で項目を参照するときは、事前に宣言しておく必要があります。ただし、サブプログラムは、その他すべてのプログラム項目の後の宣言部の末尾で宣言してください。

ENDPL/SQL ブロックの終わりを示すキーワードです。これはブロック中の 後のキーワードにする必要があります。ENDはトランザクションの終わりを通知しないことに注意してください。ブロックが複数のトランザクションにまたがることができるように、トランザクションも複数のブロックにまたがることができます。

13-14 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 423: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

EXCEPTIONPL/SQL ブロックの例外処理部の開始を示すキーワードです。例外が呼び出されると、ブロックの通常の実行が停止され、制御が適切な例外ハンドラに移ります。例外ハンドラが終了すると、ブロック直後の文から実行が再開されます。

呼び出された例外の例外ハンドラが現行のブロックに存在しないと、制御は外側のブロックに渡されます。この過程が、例外ハンドラが見つかるまで、または外側にブロックがなくなるまで繰り返されます。PL/SQL が、例外を処理するための例外ハンドラを見つけられない場合、実行は停止され、「未処理例外」エラーがホスト環境に戻されます。詳細は、第 10 章を参照してください。

exception_declaration例外を宣言します。exception_declarationの構文は、13-62 ページの「例外」を参照してください。

exception_handler例外ハンドラです。例外が呼び出されると、その例外に関連付けられた一連の文を実行します。exception_handlerの構文は、13-62 ページの「例外」を参照してください。

function_declarationファンクションを宣言します。function_declarationの構文は、13-90 ページの「ファンクション」を参照してください。

label_nameオプションとして PL/SQL ブロックに付けるラベル名で、未宣言の識別子です。label_nameを使用する場合は、二重の山カッコで囲み、ブロックの先頭に置いてください。オプションとして、label_nameを、山カッコで囲まずに、ブロックの 後に置くこともできます。

外側のブロックで宣言されたグローバル識別子を、サブブロックで再宣言できます。この場合、サブブロック内での宣言が優先され、ブロック・ラベルを使用して参照を修飾しなければ、サブブロックではグローバル識別子を参照できなくなります。次に例を示します。

<<outer>>DECLARE x INTEGER;BEGIN DECLARE x INTEGER; BEGIN IF x = outer.x THEN -- refers to global x NULL; END IF; END;END outer;/

PL/SQL の言語要素 13-15

Page 424: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

object_declarationオブジェクト型のインスタンスを宣言します。object_declarationの構文は、13-115ページの「オブジェクト型」を参照してください。

procedure_declarationプロシージャを宣言します。procedure_declarationの構文は、13-138 ページの「プロシージャ」を参照してください。

record_declarationユーザー定義のレコードを宣言します。record_declarationの構文は、13-145 ページの

「レコード」を参照してください。

statement実行可能文です(宣言文ではない)。一連の文の中には、RAISEなどのプロシージャ文、UPDATEなどの SQL 文および PL/SQL ブロックを含めることができます。

PL/SQL 文は自由形式です。つまり、PL/SQL 文は、キーワード、デリミタ、リテラルが複数の行にまたがらないかぎり、何行でも続けることができます。文の終わりは、セミコロン

(;)です。

subtype_name任意のスカラーまたは CHAR、DATE、RECORDなどのユーザー定義の PL/SQL データ型指定子を使用して定義したユーザー定義のサブタイプを識別します。

variable_declaration変数を宣言します。variable_declarationの構文は、13-39 ページの「定数と変数」を参照してください。

PL/SQL は、データ操作、カーソル制御およびトランザクション制御文を含む SQL 文のサブセットをサポートしています。ただし、ALTER、CREATE、GRANT、REVOKEなどのデータ定義およびデータ制御文はサポートしていません。

13-16 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 425: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ブロック

例例例例

次の PL/SQL ブロックでは、いくつかの変数を宣言し、計算およびファンクション・コールを含めた文を実行して、発生の可能性があるエラーを処理します。

DECLARE numerator NUMBER := 22; denominator NUMBER := 7; the_ratio NUMBER;BEGIN the_ratio := numerator/denominator; dbms_output.put_line('Ratio = ' || the_ratio);EXCEPTION WHEN ZERO_DIVIDE THEN dbms_output.put_line('Divide-by-zero error: can''t divide ' || numerator || ' by ' || denominator); WHEN OTHERS THEN dbms_output.put_line('Unexpected error.');END;/

関連項目関連項目関連項目関連項目

定数と変数、例外、ファンクション、プロシージャ

PL/SQL の言語要素 13-17

Page 426: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

CASE 文

CASE 文文文文

CASE文を使用すると、一連の条件を基に、対応する文を選択して実行できます。CASE文は、単一の式を評価していくつかの可能性のある値と比較するか、または複数のブール式を評価して 初に TRUEとなった式を選択します。

構文構文構文構文

searched_case_statement ::=

[ <<label_name>> ]CASE { WHEN boolean_expression THEN {statement;} ... }...[ ELSE {statement;}... ]END CASE [ label_name ];

simple_case_statement ::=

[ <<label_name>> ]CASE case_operand{ WHEN when_operand THEN {statement;} ... }...[ ELSE {statement;}... ]END CASE [ label_name ];

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

単純な CASE文の場合、CASEオペランドと WHENオペランドの値は、BLOB、BFILE、オブジェクト型、PL/SQL レコード、索引付き表、VARRAY またはネストした表以外であれば、任意の PL/SQL データ型にできます。

ELSE句を省略すると、デフォルトのアクションが代用されます。CASE文の場合、条件が一致しなければ、デフォルトで CASE_NOT_FOUND例外が呼び出されます。CASE式の場合は、デフォルトで NULLが戻されます。

使用上の注意使用上の注意使用上の注意使用上の注意

WHEN句は順番に実行されます。

各 WHEN句はそれぞれ 1 度のみ実行されます。

一致する WHEN句が 1 つでも見つかると、後続の WHEN句は実行されません。

WHEN句の文でデータベースを変更し、非決定的なファンクションをコールできます。

C 言語の switch文のような失敗はありません。WHEN句が一致し、その文が実行されると、CASE文は終了します。

13-18 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 427: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

CASE 文

CASE文は、オプションごとにアクションが異なる場合に適しています。複数の値から値を選択して変数に代入するのみの場合、かわりに CASE式を使用して代入文を記述できます。

たとえば、DECODEファンクション、またはある値を別の値に変換する他のファンクションをコールするかわりに、SQL 問合せ内に CASE式を含めることができます。

例例例例

次の例では、単純な CASE文を示します。WHEN句の後に複数の文を使用できることに注意してください。また、WHEN句の式にはリテラル、変数、ファンクション・コールまたはその他の任意の式を使用できることにも注意してください。

DECLARE n number := 2;BEGIN CASE n WHEN 1 THEN dbms_output.put_line('n = 1'); WHEN 2 THEN dbms_output.put_line('n = 2'); dbms_output.put_line('That implies n > 1'); WHEN 2+2 THEN dbms_output.put_line('n = 4'); ELSE dbms_output.put_line('n is some other value.'); END CASE;END;/

次の例では、検索 CASE文を示します。WHEN句では、すべての条件に同じ変数をテストしたり同じ演算子を使用するのではなく、それぞれ異なる条件を使用できることに注意してください。この例では ELSE句を使用していないため、WHEN条件が 1 つも満たされない場合は例外が呼び出されます。

DECLARE quantity NUMBER := 100; projected NUMBER := 30; needed NUMBER := 999;BEGIN<<here>> CASE WHEN quantity is null THEN dbms_output.put_line('Quantity not available'); WHEN quantity + projected >= needed THEN dbms_output.put_line('Quantity ' || quantity || ' should be enough if projections are met.'); WHEN quantity >= 0 THEN dbms_output.put_line('Quantity ' || quantity || ' is probably not enough.'); END CASE here; EXCEPTION

PL/SQL の言語要素 13-19

Page 428: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

CASE 文

WHEN CASE_NOT_FOUND THEN dbms_output.put_line('Somehow quantity is less than 0.');END;/

関連項目関連項目関連項目関連項目

4-2 ページの「条件テスト : IF 文および CASE 文」、2-32 ページの CASE 式、『Oracle Database SQL リファレンス』の NULLIF式および COALESCE式

13-20 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 429: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

CLOSE 文

CLOSE 文文文文

CLOSE文は、カーソルまたはカーソル変数からのフェッチが終了し、カーソルが占有していたリソースを再利用できるようになったことを示します。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name、、、、cursor_variable_name、、、、host_cursor_variable_nameカーソルをクローズする際、現行の有効範囲の中で事前に宣言され、現在オープンされている明示カーソルまたは PL/SQL カーソル変数を指定できます。

また、PL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数も指定できます。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

使用上の注意使用上の注意使用上の注意使用上の注意

一度クローズしたカーソルまたはカーソル変数を再オープンする場合は、それぞれ OPEN文または OPEN-FOR文を使用します。カーソルは再オープンする前に、一度クローズする必要があります。そうしないと、PL/SQL によって事前定義の例外 CURSOR_ALREADY_OPENが呼び出されます。カーソル変数を再オープンする場合は、その前にクローズする必要はありません。

すでにクローズされているか一度もオープンされたことのないカーソルまたはカーソル変数をクローズしようとすると、PL/SQL によって事前定義の例外 INVALID_CURSORが呼び出されます。

CLOSE

cursor_name

cursor_variable_name

: host_cursor_variable_name

;

close_statement

PL/SQL の言語要素 13-21

Page 430: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

CLOSE 文

例例例例DECLARE CURSOR emp_cv IS SELECT * FROM employees WHERE first_name = 'John'; emp_rec employees%ROWTYPE;BEGIN OPEN emp_cv; LOOP FETCH emp_cv INTO emp_rec; EXIT WHEN emp_cv%NOTFOUND; END LOOP; CLOSE emp_cv; /* Close cursor variable after last row is processed. */END;/

関連項目関連項目関連項目関連項目

FETCH 文、OPEN 文、OPEN-FOR 文、6-11 ページの「PL/SQL を使用したデータの問合せ」

13-22 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 431: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

コレクション・メソッドコレクション・メソッドコレクション・メソッドコレクション・メソッド

コレクション・メソッドとは、コレクションに対する操作を実行するための、ドット表記法を使用してコールされる組込みファンクションまたはプロシージャです。メソッドEXISTS、COUNT、LIMIT、FIRST、LAST、PRIOR、NEXT、EXTEND、TRIMおよびDELETEを使用して、サイズが不明または多様なコレクションを管理できます。

EXISTS、COUNT、LIMIT、FIRST、LAST、PRIORおよび NEXTは、コレクションのプロパティまたは個々のコレクション要素をチェックするファンクションです。EXTEND、TRIMおよび DELETEは、コレクションを変更するプロシージャです。

EXISTS、PRIOR、NEXT、TRIM、EXTENDおよび DELETEは整数パラメータを取ります。文字列キーを持つ結合配列の場合、EXISTS、PRIOR、NEXTおよび DELETEは、VARCHAR2パラメータも取ります。EXTENDと TRIMは、索引付き表では使用できません。

詳細は、5-30 ページの「コレクション・メソッドの使用」を参照してください。

構文構文構文構文

collection_name .

COUNT

DELETE( index

, index)

EXISTS ( index )

EXTEND( number

, index)

FIRST

LAST

LIMIT

NEXT ( index )

PRIOR ( index )

TRIM( number )

collection_method_call

PL/SQL の言語要素 13-23

Page 432: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

collection_name現行の有効範囲のうち、これより前の部分で宣言されている結合配列、ネストした表またはVARRAY を指定します。

COUNTコレクションに現在含まれている要素の数を戻します。コレクションの現行のサイズが不明な場合があるため、そのようなときに役立ちます。COUNTは、整数式が使用できる位置ならどこでも使用できます。

VARRAY の場合、COUNTは常に LASTと同じです。ネストした表の場合、COUNTは通常、LASTと同じです。ただし、ネストした表の途中から要素を削除すると、COUNTは LASTより小さくなります。

DELETEこのプロシージャには 3 つの形式があります。DELETEは、コレクションからすべての要素を削除します。DELETE(n)は、n番目の要素を結合配列またはネストした表から削除します。nが NULL である場合、DELETE(n)は何も実行しません。DELETE(m,n)は、m~ nの範囲のすべての要素を結合配列またはネストした表から削除します。mが nより大きい場合、または mか nが NULL である場合、DELETE(m,n)は何も実行しません。

EXISTSEXISTS(n)は、コレクションに n番目の要素が存在する場合に TRUEを戻します。それ以外の場合、EXISTS(n)は FALSEを戻します。主に EXISTSは、DELETEとともに、疎であるネストした表のメンテナンスのために使用します。また、EXISTSを使用すると、存在しない要素を参照した場合に呼び出される例外を回避できます。範囲外の添字を渡した場合、EXISTSは SUBSCRIPT_OUTSIDE_LIMITを呼び出さずに、FALSEを戻します。

EXTENDこのプロシージャには 3 つの形式があります。EXTENDは、コレクションに 1 つの NULL 要素を追加します。EXTEND(n)は、コレクションに n個の NULL 要素を追加します。EXTEND(n,i)は、コレクションに i番目の要素のコピーを n個追加します。

EXTENDは、コレクションの内部サイズに対して操作します。EXTENDは削除された要素を見つけると、それらの要素を数に含めます。

結合配列で EXTENDを使用することはできません。

13-24 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 433: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

FIRST、、、、LASTFIRSTと LASTは、それぞれコレクションの 初と 後( 小と 大)の添字値を戻します。通常、添字値は整数ですが、結合配列では文字列の場合もあります。コレクションが空の場合、FIRSTと LASTは NULLを戻します。コレクションに含まれる要素の数が 1 つのみの場合、FIRSTと LASTは同じ添字値を戻します。

VARRAY の場合、FIRSTは常に 1 を戻し、LASTは常に COUNTと同じです。ネストした表の場合、LASTは通常、COUNTと同じです。ただし、ネストした表の途中から要素を削除すると、LASTは COUNTより大きくなります。

indexほとんどの場合は整数が戻される(または暗黙的に整数に変換される)式、文字列キーを使用して宣言した結合配列の場合は文字列です。

LIMIT大サイズがないネストした表の場合、LIMITは NULLを戻します。VARRAY の場合、

LIMITは VARRAY に入れることのできる(型定義で指定する必要がある)要素の 大数を戻します。

NEXT、、、、PRIORPRIOR(n)は、コレクションの索引 nの前の添字を戻します。NEXT(n)は、索引 nの後の添字を戻します。nの前の番号がない場合、PRIOR(n)は NULLを戻します。同様に、nの後の番号がない場合、NEXT(n)は NULLを戻します。

TRIMこのプロシージャには 2 つの形式があります。TRIMは、コレクションの末尾から 1 つの要素を削除します。TRIM(n)は、コレクションの末尾から n個の要素を削除します。nがCOUNTより大きいと、TRIM(n)は SUBSCRIPT_BEYOND_COUNTを呼び出します。索引付き表で TRIMを使用することはできません。

TRIMは、コレクションの内部サイズに対して操作します。TRIMは削除された要素を見つけると、それらの要素を数に含めます。

PL/SQL の言語要素 13-25

Page 434: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

使用上の注意使用上の注意使用上の注意使用上の注意

コレクション・メソッドは SQL 文では使用できません。使用すると、コンパイル・エラーになります。

基本構造的に NULL であるコレクションに適用されるのは EXISTSのみです。それ以外のメソッドをそのようなコレクションに適用すると、PL/SQL は COLLECTION_IS_NULLを呼び出します。

コレクション要素の添字が連続している場合、FORループで collection.FIRST .. collection.LASTを使用して、すべての要素に対して反復処理を実行できます。

PRIORまたは NEXTを使用すると、任意の添字列を索引とするコレクション内を移動できます。たとえば、PRIORまたは NEXTを使用すると、要素をいくつか削除したネストした表内、または添字が文字列の値である結合配列内を移動できます。

EXTENDは、削除された要素を含むコレクションの内部サイズに対して操作します。EXTENDを使用して、基本構造的に NULL であるコレクションの初期化はできません。また、NOT NULL制約を TABLEまたは VARRAY型に指定した場合、EXTENDの 初の 2 つの形式はその型のコレクションに適用できません。

削除対象の要素が存在しない場合でも、DELETEは単にその要素をスキップするため、例外は呼び出されません。VARRAY は密であるため、個々の要素は削除できません。

PL/SQL は削除された要素のプレースホルダを保持するため、削除された要素に新しい値を代入して、その要素を置き換えることができます。ただし、PL/SQL は切り捨てられた

(TRIM)要素のプレースホルダは保持しません。

ネストした表に割り当てられるメモリーの量は、動的に増減します。要素を削除すると、メモリーはページ単位で解放されます。表全体を削除した場合は、すべてのメモリーが解放されます。

一般に、TRIMと DELETEの間の相互作用には依存しないでください。ネストした表は、固定サイズの配列のように扱って DELETEのみを使用するか、またはスタックのように扱ってTRIMと EXTENDのみを使用することをお薦めします。

サブプログラム内で、コレクション・パラメータは引数のプロパティがバインドされていることを前提にしています。メソッド FIRST、LAST、COUNTなどをそのようなパラメータに適用できます。VARRAY パラメータの場合、パラメータ・モードに関係なく、LIMITの値は常にパラメータの型定義から導出されます。

13-26 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 435: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

例例例例

次の例では、アクション内のすべてのコレクション・メソッドを示します。

DECLARE TYPE color_typ IS TABLE OF VARCHAR2(32); colors color_typ; i INTEGER;BEGIN colors := color_typ('red','orange','yellow','green','blue','indigo','violet');

-- Using NEXT is the most reliable way to loop through all elements. i := colors.FIRST; -- get subscript of first element WHILE i IS NOT NULL LOOP colors(i) := INITCAP(colors(i)); dbms_output.put_line('COLORS(' || i || ') = ' || colors(i)); i := colors.NEXT(i); -- get subscript of next element END LOOP;

dbms_output.put_line('Deleting yellow...');

colors.DELETE(3); -- Remove item 3. Now the subscripts are 1,2,4,5,6,7.

-- Loop goes from 1 to 7, even though item 3 has been deleted. FOR i IN colors.FIRST..colors.LAST LOOP IF colors.EXISTS(i) THEN dbms_output.put_line('COLORS(' || i || ') still exists.'); ELSE dbms_output.put_line('COLORS(' || i || ') no longer exists.'); END IF; END LOOP;

dbms_output.put_line('Deleting blue, indigo, violet...'); colors.DELETE(5,7); -- Delete items 5 through 7.

-- Loop now goes from 1 to 4, because 4 is the highest ("last") subscript. FOR i IN colors.FIRST..colors.LAST LOOP IF colors.EXISTS(i) THEN dbms_output.put_line('COLORS(' || i || ') still exists.'); ELSE dbms_output.put_line('COLORS(' || i || ') no longer exists.'); END IF; END LOOP;END;/

PL/SQL の言語要素 13-27

Page 436: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション・メソッド

次の例では、LIMITメソッドを使用して、VARRAY にいくつかの要素を追加できるかどうかをチェックします。

DECLARE TYPE chores_typ is VARRAY(4) OF VARCHAR2(32); chores chores_typ;BEGIN chores := chores_typ('Mow lawn','Wash dishes','Buy groceries'); IF (chores.COUNT + 5) <= chores.LIMIT THEN -- Add 5 more to-do items dbms_output.put_line('Adding 5 more items to CHORES.'); chores.EXTEND(5); ELSE dbms_output.put_line('Can''t extend CHORES, it can hold a maximum of ' || chores.LIMIT || ' items.'); END IF;END;/

関連項目関連項目関連項目関連項目

コレクション、ファンクション、プロシージャ

13-28 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 437: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

コレクションコレクションコレクションコレクション

コレクションは、すべて同じ型の要素の順序付きグループです(あるクラスの生徒の成績など)。各要素には一意の添字が付いています。その番号によって、集合の中での要素の位置が決まります。PL/SQL には、結合配列、ネストした表および VARRAY(可変サイズの配列)の、3 種類のコレクションがあります。ネストした表は、結合配列(以前の「PL/SQL表」または「索引付き表」)の機能を拡張します。

コレクションは、ほとんどの第 3 世代のプログラミング言語で見られる配列と同様の働きをします。コレクションにあるのは、1 次元のみです。ほとんどのコレクションは整数で索引付けされますが、結合配列では文字列も使用できます。マルチディメンション配列のモデルを作成する場合には、項目として他のコレクションを持つコレクションを宣言できます。

ネストした表や VARRAY にオブジェクト型のインスタンスを格納したり、また、逆にネストした表や VARRAY がオブジェクト型の属性であったりします。コレクションは、パラメータとして渡すこともできます。それらを使用して、データの列をデータベースの表に出し入れしたり、クライアント側アプリケーションとストアド・サブプログラムとの間でデータの列を移動できます。

詳細は、5-7 ページの「コレクション型の定義」を参照してください。

構文構文構文構文

TYPE type_name IS TABLE OF element_typeNOT NULL

table_type_definition

TYPE type_name ISVARRAY

VARRYING ARRAY( size_limit )

varray_type_definition

OF element_typeNOT NULL

;

collection_name type_name ;

collection_declaration

INDEX BY BINARY_INTEGER;

PL/SQL の言語要素 13-29

Page 438: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

element_typeBINARY_INTEGER、BOOLEAN、LONG、LONG RAW、NATURAL、NATURALN、PLS_INTEGER、POSITIVE、POSITIVEN、REF CURSOR、SIGNTYPEまたは STRING以外の PL/SQL データ型です。さらに、VARRAY では、element_typeは BLOB、CLOB、または BLOB属性か CLOB属性を持つオブジェクト型にできません。

INDEX BY type_nameオプションです。結合配列を定義します。システムで添字値を順に定義するのではなく、ユーザーが使用する添字値を指定します。

type_nameには、BINARY_INTEGER、PLS_INTEGERまたは文字列型(VARCHAR2など)を指定できます。

size_limit正の整数のリテラルであり、VARRAY の 大サイズ、つまり VARRAY に格納できる要素数の 大値を指定します。

cursor_name % ROWTYPE

db_table_name% ROWTYPE

. column_name % TYPE

object_name % TYPE

REFobject_type_name

record_name. field_name

% TYPE

record_type_name

scalar_datatype_name

variable_name % TYPE

element_type

13-30 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 439: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

type_nameデータ型指定子 TABLEまたは VARRAYを使用して定義されたユーザー定義のコレクション型を識別します。

使用上の注意使用上の注意使用上の注意使用上の注意

ネストした表は、索引付き表の機能を拡張したものであるため、いくつかの点で異なります。5-6 ページの「ネストした表と結合配列の選択」を参照してください。

すべての要素参照には、コレクション名およびカッコで囲まれた 1 つ以上の添字が含まれており、この添字によって、処理される要素が決まります。負の添字を持つことができる結合配列を除き、コレクションの添字の下限は 1(固定)です。マルチレベル・コレクションの添字は、任意の順序で評価されます。添字に、別の添字の値を変更する式が含まれている場合の結果は、未定義になります。

3 つのすべてのコレクション型は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で定義できます。ただし、CREATEを使用して作成し、Oracle データベース内に格納できるのは、ネストした表と VARRAY 型のみです。

結合配列とネストした表は疎である(添字が連続していない)場合があります。ただし、VARRAY は常に密です(添字が連続しています)。ネストした表とは異なり、VARRAY はデータベースに格納されるときにその順序と添字が保たれます。

初、結合配列は疎です。そのため、たとえば、主キー(口座番号や従業員番号など)を索引として使用して、参照データを一時変数に格納できます。

コレクションは、通常の有効範囲とインスタンス化の規則に従います。パッケージの中では、そのパッケージが初めて参照された時点でコレクションのインスタンスが生成され、データベース・セッションが終わった時点で消滅します。ブロックまたはサブプログラムの中で、ローカル・コレクションは、ブロックまたはサブプログラムに入ったときにインスタンス化され、ブロックまたはサブプログラムが終了した時点で消滅します。

ネストした表または VARRAY は、初期化するまでは基本構造的に NULL(つまりコレクションの要素ではなく、コレクション自体が NULL)です。ネストした表または VARRAYを初期化するには、コンストラクタ(コレクション型と同じ名前のシステム定義ファンクション)を使用します。このファンクションは、コレクションに渡される要素から、コレクションを構成(コンストラクト)します。

ネストした表と VARRAY は、基本構造的に NULL である場合があるため、NULL かどうかをテストできます。ただし、等価、不等価の比較はできません。この制限は、暗黙的な比較にも適用されます。たとえば、コレクションは DISTINCT、GROUP BYまたは ORDER BYリストには使用できません。

コレクションにオブジェクト型のインスタンスを格納したり、また、逆にコレクションがオブジェクト型の属性であったりします。コレクションは、パラメータとして渡すこともできます。それらを使用して、データの列をデータベースの表に出し入れしたり、クライアント側アプリケーションとストアド・サブプログラムとの間でデータの列を移動できます。

PL/SQL の言語要素 13-31

Page 440: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

コレクションを戻すファンクションをコールする場合、次の構文を使用してコレクション内の要素を参照します。

collection_name(parameter_list)(subscript)

Oracle Call Interface(OCI)または Oracle プリコンパイラを使用すると、サブプログラムの仮パラメータとして宣言された索引付き表にホスト配列をバインドできます。これによって、ホスト配列をストアド・ファンクションやプロシージャに渡すことができます。

例例例例

コレクションの要素型を指定するには、%TYPEまたは %ROWTYPEを使用します。

DECLARE TYPE JobList IS VARRAY(10) OF employees.job_id%TYPE; -- based on column TYPE EmpFile IS VARRAY(150) OF employees%ROWTYPE; -- based on database table CURSOR c1 IS SELECT * FROM departments; TYPE DeptFile IS TABLE OF c1%ROWTYPE; -- based on cursorBEGIN NULL;END;/

RECORD型を使用して、コレクションの要素型を指定することもできます。

DECLARE TYPE Entry IS RECORD ( term VARCHAR2(20), meaning VARCHAR2(200)); TYPE Glossary IS VARRAY(250) OF Entry;BEGIN NULL;END;/

次の例では、レコードの結合配列を宣言します。表の要素のそれぞれに、データベース表の行が格納されます。

DECLARE TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER; emp_tab EmpTabTyp;BEGIN /* Retrieve employee record. */ SELECT * INTO emp_tab(100) FROM employees WHERE employee_id = 100;END;/

13-32 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 441: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

VARRAY型の定義では、その 大サイズを指定する必要があります。次の例では、366 個以内の日付を格納する型を定義します。

DECLARE TYPE Calendar IS VARRAY(366) OF DATE;BEGIN NULL;END;/

一度コレクション型を定義すると、次の SQL*Plus スクリプトに示すようにしてその型のコレクションを宣言できます。

CREATE TYPE Project AS OBJECT( project_no NUMBER(2), title VARCHAR2(35), cost NUMBER(7,2));/

CREATE TYPE ProjectList AS VARRAY(50) OF Project; -- VARRAY type/

CREATE TABLE temp_department ( idnum NUMBER(2), name VARCHAR2(15), budget NUMBER(11,2), projects ProjectList);

DROP TABLE temp_department;DROP TYPE ProjectList;DROP TYPE Project;

識別子 projectsは VARRAY 全体を表します。projectsの各要素には、Projectオブジェクトが格納されます。

次の例では、ネストした表をパッケージ・プロシージャのパラメータとして宣言します。

CREATE PACKAGE personnel AS TYPE Staff IS TABLE OF Employee; PROCEDURE award_bonuses (members IN Staff);END personnel;/

DROP PACKAGE personnel;

PL/SQL の言語要素 13-33

Page 442: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コレクション

ファンクション仕様部の RETURN句の中にコレクション型を指定できます。

DECLARE TYPE SalesForce IS VARRAY(20) OF employees%ROWTYPE; FUNCTION top_performers (n INTEGER) RETURN SalesForce IS BEGIN RETURN NULL; END;BEGIN NULL;END;/

次の例では、ある部門に割り当てられているプロジェクトのリストを更新します。

-- Needs to be simplified...

DECLARE new_projects ProjectList := ProjectList(Project(1, 'Issue New Employee Badges', 13500), Project(2, 'Inspect Emergency Exits', 1900), Project(3, 'Upgrade Alarm System', 3350), Project(4, 'Analyze Local Crime Stats', 825));BEGIN UPDATE department SET projects = new_projects WHERE name = 'Security';END;/

次の例では、データベース表の VARRAY を取り出してローカル VARRAY に格納します。

-- Needs to be simplified...

DECLARE my_projects ProjectList;BEGIN SELECT projects INTO my_projects FROM department WHERE name = 'Accounting';END;/

関連項目関連項目関連項目関連項目

コレクション・メソッド、オブジェクト型、レコード

13-34 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 443: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コメント

コメントコメントコメントコメント

コメントを使用すると、コードの内容を説明する任意のテキストをコード内に含めることができます。また、廃止されたコード部分や作成途中のコード部分をコメントに入れて無効化することもできます。

PL/SQL では、単一行コメントと複数行コメントの 2 種類のコメント・スタイルがサポートされています。行の中の任意の位置(文字リテラルの中は除く)に二重ハイフン(--)を挿入すると、その行の残りの部分がコメントになります。複数行コメントは、スラッシュ - アスタリスク(/*)で始まってアスタリスク - スラッシュ(*/)で終わります。詳細は、2-9ページの「コメント」を参照してください。

構文構文構文構文

使用上の注意使用上の注意使用上の注意使用上の注意

単一行コメントは、行の末尾ならば、文の途中に置くこともできます。

単一行コメントは複数行コメント内に含めることができますが、複数行コメントはネストできません。

また、Oracle プリコンパイラ・プログラムが動的に処理する PL/SQL ブロックの中では、単一行コメントは使用できません。これは、行の終わりを示す文字が無視され、単一行コメントがブロックの終わりまで続いてしまうためです。この場合、複数行コメントを使用してください。

プログラムのテストやデバッグのときに、コード中の 1 行を無効にする場合があります。次の例では、行を「コメントにする」方法を示します。

-- UPDATE department SET location_id = my_loc WHERE department_id = my_deptno;

複数行コメントのデリミタを使用すると、コードの一部分をすべてコメントにできます。

- - text

/* text */

comment

PL/SQL の言語要素 13-35

Page 444: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

コメント

例例例例

次の例では、様々なコメント・スタイルを示します。

DECLARE area NUMBER; pi NUMBER; radius NUMBER;BEGIN -- Compute the area of a circle area := pi * radius**2; -- pi is approx. 3.14159

/* Compute the area of a circle. */ area := pi /* pi is approx. 3.14159 */ * radius**2; END;/

13-36 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 445: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

COMMIT 文

COMMIT 文文文文

COMMIT文は、カレント・トランザクションでデータベースに加えられた変更を確定します。また、コミットは変更内容が他のユーザーからも見えるようにします。詳細は、6-38ページの「PL/SQL におけるトランザクション処理の概要」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

COMMENTコメントを、カレント・トランザクションに関連付けるキーワードです。通常、分散トランザクションで使用されます。このテキストは引用符で囲んだ 50 文字以内のリテラルにしてください。

WORK見やすくする目的でのみ使用するオプションです。

使用上の注意使用上の注意使用上の注意使用上の注意

COMMIT文は、すべての行と表のロックを解除します。また、 後のコミットまたはロールバック以降にマークされたすべてのセーブポイントを消去します。変更がコミットされるまでは、次のような状況になっています。

� 自分で変更を加えた表に問合せを発行するとその変更内容が見えますが、他のユーザーから変更内容は見えません。

� 考えを変えた場合や間違いを修正する場合は、ROLLBACK文を使用して変更内容をロールバック(取消し)できます。

FOR UPDATEカーソルがオープンしているときにコミットした場合、そのカーソルでそれ以降フェッチすると例外が呼び出されます。カーソルはオープンしたままのため、クローズしてください。詳細は、6-43 ページの「FOR UPDATE の使用」を参照してください。

分散トランザクションの実行に失敗した場合は、COMMENTで指定されたテキストが問題点の診断に役立ちます。分散トランザクションがインダウトになった場合、Oracle はこのテキストをトランザクション ID とともにデータ・ディクショナリに格納します。分散トランザクションの詳細は、『Oracle Database 概要』を参照してください。

COMMITWORK COMMENT ’ text ’

;

commit_statement

PL/SQL の言語要素 13-37

Page 446: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

COMMIT 文

SQL では、FORCE句はインダウト分散トランザクションを手動でコミットする句です。PL/SQL ではこの句はサポートされていません。

COMMIT WORK FORCE '23.51.54'; -- not allowed

埋込み SQL では、RELEASEオプションは、プログラムに保持されるすべてのロックおよびカーソルを解放し、データベースから切断します。PL/SQL ではこのオプションはサポートされていません。

COMMIT WORK RELEASE; -- not allowed

関連項目関連項目関連項目関連項目

ROLLBACK 文、SAVEPOINT 文

13-38 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 447: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

定数と変数

定数と変数定数と変数定数と変数定数と変数

定数と変数は、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で宣言できます。宣言によって、値の記憶域を割り当て、データ型を指定し、参照できるように名前を指定します。また、初期値を代入したり、NOT NULL制約を付けることもできます。詳細は、2-11 ページの「宣言」を参照してください。

構文構文構文構文

variable_name datatype

NOT NULL :=

DEFAULTexpression

;

variable_declaration

collection_name % TYPE

collection_type_name

cursor_name % ROWTYPE

cursor_variable_name % TYPE

db_table_name% ROWTYPE

. column_name % TYPE

object_name % TYPE

REFobject_type_name

record_name % TYPE

record_type_name

ref_cursor_type_name

scalar_datatype_name

variable_name % TYPE

datatype

PL/SQL の言語要素 13-39

Page 448: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

定数と変数

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

collection_name現行の有効範囲のうち、これより前の部分で宣言されているコレクション(結合配列、ネストした表または VARRAY)を識別します。

collection_type_nameデータ型指定子 TABLEまたは VARRAYを使用して定義されたユーザー定義のコレクション型を識別します。

CONSTANT定数の宣言であることを示します。定数は宣言部で初期化してください。初期化された定数の値は変更できません。

constant_nameプログラム定数を識別します。ネーミング規則は、2-4 ページの「識別子」を参照してください。

cursor_name現行の有効範囲の中で事前に宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で事前に宣言されている PL/SQL カーソル変数を識別します。

db_table_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要があるデータベースの表(またはビュー)を識別します。

db_table_name.column_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要があるデータベースの表および列を識別します。

NOT NULL :=

DEFAULTexpression ;constant_name CONSTANT datatype

constant_declaration

13-40 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 449: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

定数と変数

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。宣言が PL/SQL コンパイラによって処理されるとき、expressionの値が定数または変数に代入されます。その値と定数または変数のデータ型には互換性が必要です。

NOT NULLプログラムで NULL 値を変数または定数に代入できないようにするための制約です。NOT NULLとして定義された変数に NULL を代入しようとすると、事前定義の例外VALUE_ERRORが呼び出されます。NOT NULL制約の後には初期化句が続く必要があります。

object_name現行の有効範囲のうち、これより前の部分で宣言されているオブジェクト型のインスタンスを識別します。

record_name現行の有効範囲のうち、これより前に宣言されているユーザー定義のレコードまたは%ROWTYPEレコードを識別します。

record_name.field_name現行の有効範囲のうち、これより前に宣言されているユーザー定義のレコードまたは%ROWTYPEレコードのフィールドを識別します。

record_type_nameデータ型指定子 RECORDを使用して定義するユーザー定義のレコード型を識別します。

ref_cursor_type_nameデータ型指定子 REF CURSORを使用して定義されたユーザー定義のカーソル変数型を識別します。

%ROWTYPEデータベース表の中の行、またはカーソルを保持できるレコードを表します。レコードの中のフィールドと行の中の列は、同じ名前とデータ型を持ちます。

scalar_datatype_name事前定義済のスカラー・データ型(BOOLEAN、NUMBER、VARCHAR2など)を識別します。サイズ、精度、または文字とバイトのセマンティクスの修飾子が含まれます。

PL/SQL の言語要素 13-41

Page 450: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

定数と変数

%TYPEこれより前に宣言されたコレクション、カーソル変数、フィールド、オブジェクト、レコード、データベース列または変数のデータ型を表します。

variable_nameプログラム変数を識別します。

使用上の注意使用上の注意使用上の注意使用上の注意

定数と変数は、ブロックまたはサブプログラムに入るたびに初期化されます。デフォルトでは、変数は NULLに初期化されます。

パッケージの仕様部で宣言された定数と変数は、パブリックであるかプライベートであるかにかかわらず、セッションごとに 1 回のみ初期化されます。

NOT NULL変数を宣言する場合、および定数を宣言する場合には、必ず初期化の句が必要です。%ROWTYPEを使用して変数を宣言する場合は、初期化できません。

代入値を戻すファンクションをコールして、リテラル値または事前定義済コンストラクタを持たない複合型の定数を定義できます。たとえば、この方法で定数の結合配列を作成できます。

例例例例

変数と定数の宣言の例をいくつか示します。

credit_limit CONSTANT NUMBER := 5000;invalid BOOLEAN := FALSE;acct_id INTEGER(4) NOT NULL DEFAULT 9999;pi CONSTANT REAL := 3.14159;postal_code VARCHAR2(20);last_name VARCHAR2(20 CHAR);my_ename emp.ename%TYPE;

関連項目関連項目関連項目関連項目

2-11 ページの「宣言」、3-2 ページの「事前定義された PL/SQL データ型の概要」、代入文、式、%ROWTYPE 属性、%TYPE 属性

13-42 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 451: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性

カーソル属性カーソル属性カーソル属性カーソル属性

どの明示カーソルおよびカーソル変数にも %FOUND、%ISOPEN、%NOTFOUNDおよび%ROWCOUNTの 4 つの属性があります。これらの属性をカーソルまたはカーソル変数に付加すると、DML 文の実行について役立つ情報が戻されます。詳細は、6-35 ページの「カーソル式の使用」を参照してください。

暗黙カーソル SQLにはさらに属性 %BULK_ROWCOUNTおよび %BULK_EXCEPTIONSがあります。詳細は、13-172 ページの「SQL カーソル」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で、事前に宣言されている PL/SQL カーソル変数(またはパラメータ)を識別します。

%FOUND 属性属性属性属性

カーソル属性で、カーソルまたはカーソル変数の名前に追加できます。カーソルがオープンされてから 初のフェッチまでの cursor_name%FOUNDは、NULLを戻します。その後、直前のフェッチが行を戻した場合は TRUEを戻し、直前のフェッチが行を戻さなかった場合はFALSEを戻します。

host_cursor_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

cursor_name

cursor_variable_name

: host_cursor_variable_name

%

FOUND

ISOPEN

NOTFOUND

ROWCOUNT

cursor_attribute

PL/SQL の言語要素 13-43

Page 452: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性

%ISOPEN 属性属性属性属性カーソル属性で、カーソルまたはカーソル変数の名前に追加できます。カーソルがオープンされていると、cursor_name%ISOPENは TRUEを戻し、それ以外の場合は FALSEを戻します。

%NOTFOUND 属性属性属性属性

カーソル属性で、カーソルまたはカーソル変数の名前に追加できます。カーソルがオープンされてから 初のフェッチまでの cursor_name%NOTFOUNDは、NULLを戻します。その後、直前のフェッチが行を戻した場合は FALSEを戻し、直前のフェッチが行を戻さなかった場合は TRUEを戻します。

%ROWCOUNT 属性属性属性属性カーソル属性で、カーソルまたはカーソル変数の名前に追加できます。カーソルがオープンされると %ROWCOUNTは 0(ゼロ)になります。 初のフェッチまでは、cursor_name%ROWCOUNTは 0(ゼロ)を戻します。その後は、これまでにフェッチした行数を戻します。フェッチで行が戻されるたびに、数値は増加します。

使用上の注意使用上の注意使用上の注意使用上の注意

カーソルの属性は、すべてのカーソルおよびカーソル変数に適用されます。たとえば、複数のカーソルをオープンし、%FOUNDまたは %NOTFOUNDを使用して、まだフェッチしていない行が残っているカーソルがどれかを判別できます。同様に、%ROWCOUNTを使用して、これまでにフェッチした行の数を知ることができます。

カーソルまたはカーソル変数をオープンしていない場合、%FOUND、%NOTFOUNDあるいは%ROWCOUNTでカーソルやカーソル変数を参照すると、事前定義の例外 INVALID_CURSORが呼び出されます。

カーソルまたはカーソル変数をオープンすると、対応する問合せを満たす行が識別され、結果セットが形成されます。行は、結果セットから一度に 1 行ずつフェッチされます。

SELECT INTO文が複数の行を戻した場合、PL/SQL によって事前定義の例外TOO_MANY_ROWSが呼び出され、%ROWCOUNTは、問合せを満たす行の実数ではなく、1 に設定されます。

初のフェッチの前は、%NOTFOUNDの評価結果は NULLです。FETCHが正常に実行されない場合は、EXIT WHEN条件が TRUEとならず、ループは終了しません。安全のために、次の EXIT文をかわりに使用できます。

EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;

カーソルの属性は、プロシージャ文では使用できますが、SQL 文では使用できません。

13-44 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 453: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性

例例例例

次の PL/SQL ブロックでは、%FOUNDを使用してアクションを選択します。

DECLARE CURSOR emp_cur IS SELECT * FROM employees ORDER BY employee_id; emp_rec employees%ROWTYPE;BEGIN OPEN emp_cur; LOOP -- loop through the table and get each employee FETCH emp_cur INTO emp_rec; IF emp_cur%FOUND THEN dbms_output.put_line('Employee #' || emp_rec.employee_id || ' is ' || emp_rec.last_name); ELSE dbms_output.put_line('--- Finished processing employees ---'); EXIT; END IF; END LOOP; CLOSE emp_cur;END;/

次の例では、IF文の中で %FOUNDを使用するかわりに、EXIT WHEN文の中で %NOTFOUNDを使用します。

DECLARE CURSOR emp_cur IS SELECT * FROM employees ORDER BY employee_id; emp_rec employees%ROWTYPE;BEGIN OPEN emp_cur; LOOP -- loop through the table and get each employee FETCH emp_cur INTO emp_rec; EXIT WHEN emp_cur%NOTFOUND; dbms_output.put_line('Employee #' || emp_rec.employee_id || ' is ' || emp_rec.last_name); END LOOP; CLOSE emp_cur;END;/

次の例では、%ISOPENを使用して判別を行います。

IF NOT (emp_cur%ISOPEN) THEN OPEN emp_cur;END IF;FETCH emp_cur INTO emp_rec;

PL/SQL の言語要素 13-45

Page 454: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル属性

次の PL/SQL ブロックでは、%ROWCOUNTを使用して、給与が も高い 5 人の従業員の名前と給与をフェッチします。

DECLARE CURSOR c1 is SELECT last_name, employee_id, salary FROM employees ORDER BY salary DESC; -- start with highest-paid employee my_name employees.last_name%TYPE; my_empno employees.employee_id%TYPE; my_sal employees.salary%TYPE;BEGIN OPEN c1; LOOP FETCH c1 INTO my_name, my_empno, my_sal; EXIT WHEN (c1%ROWCOUNT > 5) OR (c1%NOTFOUND); dbms_output.put_line('Employee ' || my_name || ' (' || my_empno || ') makes ' || my_sal); END LOOP; CLOSE c1;END;/

次の例では、多くの行が削除された場合に例外を呼び出します。

DELETE FROM accts WHERE status = 'BAD DEBT';IF SQL%ROWCOUNT > 10 THEN RAISE out_of_bounds;

END IF;

関連項目関連項目関連項目関連項目

カーソル、カーソル変数

13-46 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 455: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

カーソル変数カーソル変数カーソル変数カーソル変数

複数行の問合せを実行するために、Oracle は処理情報を格納する名前の付けられていない作業領域をオープンします。この領域にアクセスするには、作業領域の名前を示す明示カーソル、または作業領域を指すカーソル変数を使用します。カーソル変数を作成するには、REF CURSOR型を定義してから、その型のカーソル変数を宣言します。

カーソル変数は、C や Pascal のポインタに類似しており、項目のかわりに項目のアドレスを保持します。カーソル変数を宣言すると、項目ではなくポインタが作成されます。

詳細は、6-25 ページの「カーソル変数(REF CURSOR)の使用」を参照してください。

構文構文構文構文

TYPE type_name IS REF CURSOR

ref_cursor_type_definition

cursor_variable_name type_name ;

cursor_variable_declaration

RETURN

db_table_name

cursor_name

cursor_variable_name

% ROWTYPE

record_name % TYPE

record_type_name

ref_cursor_type_name;

PL/SQL の言語要素 13-47

Page 456: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で事前に宣言されている PL/SQL カーソル変数を識別します。

db_table_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要があるデータベースの表またはビューを識別します。

record_name現行の有効範囲の中で事前に宣言されているユーザー定義のレコードを識別します。

record_type_nameデータ型指定子 RECORDを使用して定義されたユーザー定義のレコード型を識別します。

REF CURSORすべてのカーソル変数がデータ型 REF CURSORに属します。

RETURNカーソル変数の戻り値のデータ型を指定します。RETURN句で %ROWTYPE属性を使用すると、データベース表の行や、カーソルまたは強い型指定のカーソル変数によって戻される行を表すレコード型を与えることができます。また、%TYPE属性を使用して、事前に宣言されたレコードのデータ型を与えることもできます。

%ROWTYPEデータベース表の中の行、またはカーソルや強い型指定のカーソル変数からフェッチされる行を表すレコード型を指定します。レコードの中のフィールドと、それに対応する行の中の列は、同じ名前とデータ型を持ちます。

%TYPE事前に宣言されているユーザー定義のレコードのデータ型を指定します。

type_nameREF CURSORとして定義されたユーザー定義のカーソル変数型を識別します。

13-48 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 457: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

使用上の注意使用上の注意使用上の注意使用上の注意

カーソル変数は、すべての PL/SQL クライアントで使用します。たとえば、OCI や Pro*Cプログラムなどの PL/SQL ホスト環境の中でカーソル変数を宣言し、それをバインド変数として PL/SQL に渡すことができます。PL/SQL エンジンを備えたアプリケーション開発ツールでは、クライアント側でカーソル変数を完全に使用できます。

データベース・リンクによるリモート・プロシージャ・コールを通じて、アプリケーションとデータベース・サーバーの間でカーソル変数をやり取りできます。クライアント側にPL/SQL エンジンがあれば、どちらの側でもカーソル変数を使用できます。たとえば、クライアント側でカーソル変数を宣言し、それをサーバー側でオープンしてフェッチした後で、クライアント側で引き続きフェッチすることができます。

カーソル変数は、PL/SQL のストアド・サブプログラムとクライアント・プログラムとの間で問合せの結果セットを渡すために使用します。PL/SQL とクライアント・プログラムはどちらも結果セットを所有せず、結果セットが格納されている作業領域を指すポインタを共有しています。たとえば、OCI プログラム、Oracle Forms アプリケーションおよびデータベースがすべて同じ作業領域を参照する場合があります。

REF CURSOR型には、強いものと弱いものがあります。強い REF CURSOR型定義では戻り型を指定しますが、弱い型定義では戻り型を指定しません。強い REF CURSOR型の方が、エラー発生の可能性は少なくなります。これは、PL/SQL の場合、強い型指定のカーソル変数は型互換性のある問合せにしか関連付けることができないためです。弱い REF CURSOR型は、より柔軟です。弱い型指定のカーソル変数は、どの問合せにも関連付けることができます。

REF CURSOR型を一度定義すれば、その型のカーソル変数を宣言できます。%TYPEを使用すると、レコード変数のデータ型を与えることができます。また、REF CURSOR型定義のRETURN句では、%ROWTYPEを使用して、強い型指定(弱い型指定ではなく)のカーソル変数によって戻される行を表すレコード型を指定できます。

現在のところ、カーソル変数にはいくつかの制限があります。6-35 ページの「カーソル変数の制限」を参照してください。

カーソル変数の制御には、OPEN-FOR、FETCHおよび CLOSEの 3 つの文を使用します。まず、OPEN-FOR文でカーソル変数を複数行問合せ用にオープンします。次に、FETCH文で結果セットから行を取り出します。すべての行が処理された後に、CLOSE文でカーソル変数をクローズします。

その他の OPEN-FOR文は、異なる複数の問合せ用に同じカーソル変数をオープンできます。カーソル変数を再オープンする場合、その前にクローズする必要はありません。別の問合せ用にカーソル変数を再オープンすると、前の問合せは失われます。

PL/SQL では、カーソル変数の戻り型が、必ず FETCH文の INTO句と互換性を持ちます。カーソル変数に関連付けられた問合せが戻す列の値に対して、INTO句の中に、対応する、型互換性のあるフィールドまたは変数が存在している必要があります。また、フィールドまたは変数の数は、列の値の数と一致する必要があります。それ以外の場合はエラーになります。

PL/SQL の言語要素 13-49

Page 458: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

代入に関係する両方のカーソル変数が強い型指定である場合は、両方が同じデータ型であることが必要です。ただし、一方または両方のカーソル変数が弱い型指定である場合は、同じデータ型でなくてもかまいません。

カーソル変数を、そのカーソル変数からフェッチするか、またはそのカーソル変数をクローズするサブプログラムの仮パラメータとして宣言する場合は、INまたは IN OUTモードを指定する必要があります。サブプログラムがカーソル変数をオープンする場合は、IN OUTモードを指定する必要があります。

カーソル変数をパラメータとして渡す場合は注意が必要です。実パラメータと仮パラメータの戻り型に互換性がないと、実行時に PL/SQL によって ROWTYPE_MISMATCHが呼び出されます。

カーソル属性 %FOUND、%NOTFOUND、%ISOPEN、%ROWCOUNTをカーソル変数に適用できます。

問合せ作業領域を指していないカーソル変数に対してフェッチまたはクローズを実行するか、カーソルの属性を適用しようとすると、PL/SQL によって事前定義の例外INVALID_CURSORが呼び出されます。カーソル変数(またはパラメータ)が問合せ作業領域を指すようにするには、次の 2 通りの方法があります。

� OPEN-FOR文でカーソル変数を問合せ用にオープンします。

� OPEN文ですでにオープンされたホスト・カーソル変数または PL/SQL カーソル変数の値を、カーソル変数に代入します。

問合せ作業領域は、それを指すカーソル変数が存在するかぎりアクセスできます。したがって、カーソル変数の値は、1 つの有効範囲から別の有効範囲へ自由に渡すことができます。たとえば、Pro*C プログラムに組み込まれた PL/SQL ブロックにホスト・カーソル変数を渡す場合、カーソル変数が指す作業領域は、そのブロックの終了後もアクセス可能な状態のままです。

13-50 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 459: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

例例例例

OCI や Pro*C プログラムなどの PL/SQL ホスト環境で、カーソル変数を宣言できます。ホスト・カーソル変数を使用する場合は、それをバインド変数として PL/SQL に渡す必要があります。次の Pro*C の例では、ホスト・カーソル変数と選択子を PL/SQL ブロックに渡すことで、選択した問合せ用のカーソル変数をオープンします。

EXEC SQL BEGIN DECLARE SECTION; /* Declare host cursor variable. */ SQL_CURSOR generic_cv; int choice;EXEC SQL END DECLARE SECTION;/* Initialize host cursor variable. */EXEC SQL ALLOCATE :generic_cv;/* Pass host cursor variable and selector to PL/SQL block. */EXEC SQL EXECUTEBEGIN IF :choice = 1 THEN OPEN :generic_cv FOR SELECT * FROM emp; ELSIF :choice = 2 THEN OPEN :generic_cv FOR SELECT * FROM dept; ELSIF :choice = 3 THEN OPEN :generic_cv FOR SELECT * FROM salgrade; END IF;END;END-EXEC;

ホスト・カーソル変数はすべての問合せの戻り型と互換性があります。ホスト・カーソル変数は、弱い型指定の PL/SQL カーソル変数と同じように動作します。

ホスト・カーソル変数を PL/SQL に渡す場合、OPEN-FOR文をグループ化することでネットワークの通信量を削減できます。たとえば、次の PL/SQL ブロックでは、1 回の往復で 3 つのカーソル変数をオープンします。

/* anonymous PL/SQL block in host environment */ BEGIN OPEN :emp_cv FOR SELECT * FROM emp; OPEN :dept_cv FOR SELECT * FROM dept; OPEN :grade_cv FOR SELECT * FROM salgrade; END;

また、カーソル変数を仮パラメータの 1 つとして宣言するストアド・プロシージャをコールしても、カーソル変数を PL/SQL に渡すことができます。データ検索を集中的にするために、次の例のように、型互換性のある問合せをパッケージ・プロシージャの中でグループにまとめることができます。

CREATE PACKAGE emp_data AS TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE;

PL/SQL の言語要素 13-51

Page 460: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル変数

PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice IN NUMBER);END emp_data;/CREATE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice IN NUMBER) IS BEGIN IF choice = 1 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE commission_pct IS NOT NULL; ELSIF choice = 2 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE salary > 2500; ELSIF choice = 3 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE department_id = 20; END IF; END open_emp_cv;END emp_data;/DROP PACKAGE emp_data;

スタンドアロン・プロシージャを使用してカーソル変数をオープンする方法もあります。前述の例と同様にパッケージの中で REF CURSOR型を定義して、スタンドアロン・プロシージャの中でその型を参照します。

関連項目関連項目関連項目関連項目

CLOSE 文、カーソル属性、カーソル、FETCH 文、OPEN-FOR 文

13-52 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 461: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル

カーソルカーソルカーソルカーソル

複数行の問合せを実行するために、Oracle は処理情報を格納する名前の付けられていない作業領域をオープンします。カーソルを使用すると、作業領域の名前付け、情報へのアクセス、行の個別処理が可能です。詳細は、6-11 ページの「PL/SQL を使用したデータの問合せ」を参照してください。

構文構文構文構文

CURSOR cursor_name( cursor_parameter_declaration

,

)

cursor_body

RETURN rowtype IS select_statement ;

CURSOR cursor_name( cursor_parameter_declaration

,

)

cursor_spec

RETURN rowtype ;

CURSOR cursor_name( cursor_parameter_declaration

,

)

cursor_declaration

RETURN rowtypeIS select_statement ;

parameter_nameIN

datatype

:=

DEFAULTexpression

cursor_parameter_declaration

PL/SQL の言語要素 13-53

Page 462: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。

datatype型指定子です。datatypeの構文は、13-39 ページの「定数と変数」を参照してください。

db_table_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要があるデータベースの表(またはビュー)を識別します。

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。宣言が PL/SQL コンパイラによって処理されると、expressionの値がパラメータに代入されます。その値とパラメータのデータ型には互換性が必要です。

parameter_nameカーソルの仮パラメータとして宣言された変数を識別します。カーソルのパラメータは、問合せの中で定数が使用できる場所であれば、どこででも使用できます。カーソルの仮パラメータは INパラメータにしてください。問合せは、有効範囲の他の PL/SQL 変数を参照することもできます。

record_name現行の有効範囲の中で事前に宣言されているユーザー定義のレコードを識別します。

record_type_nameデータ型指定子 RECORDを使用して定義されたユーザー定義のレコード型を識別します。

db_table_name

cursor_name

cursor_variable_name

% ROWTYPE

record_name % TYPE

record_type_name

rowtype

13-54 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 463: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル

RETURNカーソルの戻り値のデータ型を指定します。RETURN句で %ROWTYPE属性を使用すると、データベースの表の行や、事前に宣言されたカーソルによって戻される行を表すレコード型を与えることができます。また、%TYPE属性を使用して、事前に宣言されたレコードのデータ型を与えることもできます。

カーソル本体には、SELECT文と、対応するカーソル仕様部と同じ RETURN句が必要です。さらに、SELECT句の中の選択項目の数、順序およびデータ型は、RETURN句と一致している必要があります。

%ROWTYPEデータベース表の中の行、または事前に宣言されたカーソルやカーソル変数からフェッチされる行を表すレコード型を指定します。レコードの中のフィールドと、それに対応する行の中の列は、同じ名前とデータ型を持ちます。

select_statement行の結果セットを戻す問合せです。構文は select_into_statementの構文と似ていますが、INTO句は使用できません。13-162 ページの「SELECT INTO 文」を参照してください。カーソル宣言でパラメータを宣言した場合は、すべてのパラメータを問合せで使用する必要があります。

%TYPE事前に宣言されているユーザー定義のレコードのデータ型を指定します。

使用上の注意使用上の注意使用上の注意使用上の注意

OPEN文、FETCH文または CLOSE文でカーソルを参照する前に、そのカーソルを宣言します。カーソル宣言で変数を参照する前に、その変数を宣言します。SQL という語は、暗黙カーソルのデフォルト名として PL/SQL によって予約されており、カーソル宣言の中では使用できません。

カーソル名に値を代入したり、カーソル名を式の中で使用することはできません。ただし、カーソルの有効範囲規則は変数の有効範囲規則と同じです。詳細は、2-19 ページの

「PL/SQL の識別子の有効範囲と可視性」を参照してください。

カーソルからデータを取り出す場合は、まずカーソルをオープンし、そこからフェッチします。FETCH文ではターゲットとなる変数を指定するため、cursor_declarationのSELECT文で INTO句を使用するのは冗長かつ誤りです。

カーソルのパラメータの有効範囲は、カーソルに対してローカルです。つまり、カーソル宣言の中で使用されている問合せの内側からしか参照できません。カーソルのパラメータ値は、カーソルがオープンされているときに、カーソルに関連付けられた問合せから使用できます。問合せは、有効範囲の他の PL/SQL 変数を参照することもできます。

カーソルのパラメータのデータ型は、無制約で指定する必要があります(数値の精度と位取り、および文字列の長さは指定しません)。

PL/SQL の言語要素 13-55

Page 464: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

カーソル

例例例例

カーソル宣言の例を示します。

CURSOR c1 IS SELECT empno, ename, job, sal FROM emp WHERE sal > 2000; CURSOR c2 RETURN dept%ROWTYPE IS SELECT * FROM dept WHERE deptno = 10;CURSOR c3 (start_date DATE) IS SELECT empno, sal FROM emp WHERE hiredate > start_date;

関連項目関連項目関連項目関連項目

CLOSE 文、FETCH 文、OPEN 文、SELECT INTO 文

13-56 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 465: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DELETE 文

DELETE 文文文文

DELETE文は、指定された表またはビューから、行のデータを削除します。DELETE 文の詳細は、『Oracle Database SQL リファレンス』を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

alias参照される表またはビューの別名(通常は短縮名)です。通常、WHERE句の中で参照されます。

WHEREsearch_condition

CURRENT OF cursor_name returning_clause;

schema_name . db_table_name

view_name

@ dblink_name

table_reference

RETURNING

single_row_expression

,

INTOvariable_name

: host_variable_name

,

multiple_row_expression

,BULK COLLECT

INTOcollection_name

: host_array_name

,

returning_clause

delete_statement

DELETEFROM

( subquery

TABLE ( subquery2 )

aliastable_reference

)

PL/SQL の言語要素 13-57

Page 466: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DELETE 文

BULK COLLECTRETURNING INTOリストで指定した場合と同様に、削除された行から PL/SQL コレクションに列を戻します。対応する列には、(複合値ではなく)スカラー値が格納されている必要があります。詳細は、11-9 ページの「DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)」を参照してください。

returning_clause削除された行から値を戻します。そのため、 初に行を SELECTで選択しておく必要はありません。取り出した列値は、個々の変数またはコレクションに代入できます。RETURNING句はリモートまたはパラレルでの削除には使用できません。文を実行しても行に影響がない場合、RETURNING句で指定した変数の値は未定義になります。

subquery処理する行セットを提供する SELECT文です。構文は select_into_statementの構文と似ていますが、INTO句は使用できません。13-162 ページの「SELECT INTO 文」を参照してください。

table_reference表またはビューを指定します。指定された表またはビューは、DELETE文の実行時にアクセスできる必要があり、ユーザーは DELETE権限を持つ必要があります。

TABLE (subquery2)TABLEのオペランドは、1 つの列値を戻す SELECT文です。これはネストした表である必要があります。演算子 TABLEは、値がスカラー値ではなくコレクションであることを Oracleに通知します。

WHERE CURRENT OF cursor_namecursor_nameで識別されるカーソルに関連付けられている FETCH文によって処理された

後の行を参照します。カーソルは、FOR UPDATEであること、さらにオープンされていて行に置かれていることが必要です。カーソルがオープンされていないと、CURRENT OF句でエラーが発生します。

カーソルがオープンされていても、フェッチされた行がないか、 後のフェッチで行が戻されなかった場合は、PL/SQL によって事前定義の例外 NO_DATA_FOUNDが呼び出されます。

WHERE search_condition参照された表またはビューから削除する行を条件に従って選択します。検索条件を満たす行のみが削除されます。WHERE句を省略すると、表またはビューのすべての行が削除されます。

13-58 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 467: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DELETE 文

使用上の注意使用上の注意使用上の注意使用上の注意

DELETE WHERE CURRENT OF文は、オープンされているカーソルからのフェッチ(カーソルFORループで実行される暗黙的なフェッチを含む)の後で使用できます。ただし、そのためには、関連付けられた問合せが FOR UPDATEであることが必要です。この文は現在行、つまり直前にフェッチされた行を削除します。

暗黙カーソル SQLと、カーソル属性 %NOTFOUND、%FOUNDおよび %ROWCOUNTを使用すると、DELETE文の実行に関する有用な情報にアクセスできます。

例例例例

次の文では、条件と一致する行を削除します。

DELETE FROM bonus WHERE sales_amt < quota;

次の文では、削除された行からローカル変数に 2 つの列値を戻します。

DECLARE my_empno emp.empno%TYPE; my_ename emp.ename%TYPE; my_job emp.job%TYPE;BEGIN ... DELETE FROM emp WHERE empno = my_empno RETURNING ename, job INTO my_ename, my_job;END;

BULK COLLECT句を FORALL文と組み合せることができます。この場合、SQL エンジンは列値を段階的にバルク・バインドします。次の例では、コレクション deptsに 3 つの要素があり、それぞれによって 5 行ずつ削除される場合、コレクション enumsは、文が完了すると 15 の要素を持ちます。

FORALL j IN depts.FIRST..depts.LAST DELETE FROM emp WHERE deptno = depts(j) RETURNING empno BULK COLLECT INTO enums;

各実行によって戻された列の値は、前に戻された値に追加されます。

関連項目関連項目関連項目関連項目

FETCH 文、INSERT 文、SELECT INTO 文、UPDATE 文

PL/SQL の言語要素 13-59

Page 468: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXCEPTION_INIT プラグマ

EXCEPTION_INIT プラグマプラグマプラグマプラグマ

EXCEPTION_INITプラグマは、例外名を Oracle エラー番号に関連付けます。OTHERSハンドラを使用するかわりに、ORA- エラーを回避し、専用のハンドラを作成できます。詳細は、10-9 ページの「PL/SQL 例外と番号の関連付け : EXCEPTION_INIT プラグマ」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

error_number任意の有効な Oracle エラー番号です。これは SQLCODEファンクションが戻すエラー番号

(常に負の値)と同じです。

exception_name現行の有効範囲の中で宣言されているユーザー定義の例外を識別します。

PRAGMA文がコンパイラ・ディレクティブであることを表します。

使用上の注意使用上の注意使用上の注意使用上の注意

EXCEPTION_INITは、任意の PL/SQL ブロック、サブプログラムまたはパッケージの宣言部で使用できます。このプラグマは、関連付けられた例外と同じ宣言部の中で、例外宣言の後のどこかに指定する必要があります。

1 つのエラー番号に割り当てる例外名は 1 つのみです。

PRAGMA EXCEPTION_INIT ( exception_name , error_number ) ;

exception_init_pragma

13-60 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 469: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXCEPTION_INIT プラグマ

例例例例

次のプラグマでは、例外 deadlock_detectedを Oracle エラー 60 に関連付けます。

DECLARE deadlock_detected EXCEPTION; PRAGMA EXCEPTION_INIT(deadlock_detected, -60);BEGIN ...EXCEPTION WHEN deadlock_detected THEN -- handle the error ...END;

関連項目関連項目関連項目関連項目

AUTONOMOUS_TRANSACTION プラグマ、例外、SQLCODE ファンクション

PL/SQL の言語要素 13-61

Page 470: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

例外

例外例外例外例外

例外は、事前定義またはユーザー定義可能な、ランタイム・エラーまたは警告状態です。事前定義の例外は実行時システムによって暗黙的(自動的)に呼び出されます。ユーザー定義の例外は RAISE文によって明示的に呼び出す必要があります。呼び出された例外を処理するには、例外ハンドラと呼ばれる独立したルーチンを作成します。詳細は、第 10 章を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

exception_nameZERO_DIVIDEのような事前定義の例外、または現行の有効範囲の中で事前に宣言されているユーザー定義の例外を識別します。

OTHERSブロックの例外処理部で明示的に名前を指定していないすべての例外を表します。OTHERSの使用はオプションで、ブロックの 後の例外ハンドラとしてのみ使用できます。キーワード WHENに続く例外のリストの中では、OTHERSを使用できません。

statement実行可能文です。statementの構文は、13-11 ページの「ブロック」を参照してください。

WHEN例外ハンドラの開始を知らせるキーワードです。キーワード WHENに続けて、キーワードORで区切った例外のリストを指定すると、複数の例外で一連の同一文を実行できます。リスト中のいずれかの例外が呼び出されると、それに関連付けられた文が実行されます。

exception_name EXCEPTION ;

exception_declaration

WHENexception_name

OR exception_name

OTHERSTHEN statement

exception_handler

13-62 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 471: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

例外

使用上の注意使用上の注意使用上の注意使用上の注意

例外宣言はブロック、サブプログラム、またはパッケージの宣言部でのみ使用できます。例外の有効範囲の規則は変数と同じです。ただし、変数とは異なり、例外をパラメータとしてサブプログラムに渡すことができません。

例外のいくつかは PL/SQL によって事前に定義されています。これらの例外のリストは、10-5 ページの「事前定義の PL/SQL 例外のまとめ」を参照してください。PL/SQL は、事前定義済の例外をパッケージ STANDARDでグローバルに宣言しているため、ユーザーが宣言する必要はありません。

事前定義の例外を再宣言すると、ローカルな宣言がグローバルな宣言をオーバーライドするため、エラーが発生しやすくなります。この場合は、ドット表記法を使用して、次のように事前定義の例外を指定する必要があります。

EXCEPTION WHEN invalid_number OR STANDARD.INVALID_NUMBER THEN ...

PL/SQL ブロックの例外処理部はオプションです。例外ハンドラはブロックの末尾に置く必要があります。例外処理部はキーワード EXCEPTIONで始まります。ブロックの例外処理部の終わりは、ブロックの終わりも示すキーワード ENDです。例外ハンドラから参照できる変数は、カレント・ブロックから参照できる変数のみです。

例外を呼び出すのは、処理の続行が不可能、あるいは望ましくないようなエラーが発生した場合のみにしてください。呼び出された例外に対応する例外ハンドラがカレント・ブロックに存在しない場合、例外は次の規則に従って伝播します。

� カレント・ブロックの外側にブロックがある場合、例外はそのブロックに渡されます。この場合、例外が渡されたブロックがカレント・ブロックになります。呼び出された例外に対応するハンドラが見つからない場合は、この過程が繰り返されます。

� カレント・ブロックの外側にブロックがない場合、「未処理例外」エラーがホスト環境に戻されます。

ブロックの例外処理部でアクティブになれる例外は一度に 1 つのみです。このため、ハンドラの内側で例外が呼び出されると、カレント・ブロックの外側のブロックが、新しく呼び出された例外に対するハンドラを検索するための 初のブロックになります。それ以降の例外の伝播は通常どおりに行われます。

PL/SQL の言語要素 13-63

Page 472: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

例外

例例例例

次の PL/SQL ブロックには 2 つの例外ハンドラがあります。

DECLARE bad_emp_id EXCEPTION; bad_acct_no EXCEPTION; ...BEGIN ...EXCEPTION WHEN bad_emp_id OR bad_acct_no THEN -- user-defined ROLLBACK; WHEN ZERO_DIVIDE THEN -- predefined INSERT INTO inventory VALUES (part_number, quantity); COMMIT;END;

関連項目関連項目関連項目関連項目

ブロック、EXCEPTION_INIT プラグマ、RAISE 文

13-64 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 473: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文

EXECUTE IMMEDIATE 文文文文

EXECUTE IMMEDIATE文は、動的 SQL 文または無名 PL/SQL ブロックを実行します。この文を使用すると、PL/SQL で直接表せない SQL 文を発行したり、一部の表名、WHERE 句などが事前に不明な場合でも文を作成できます。詳細は、第 7 章を参照してください。

構文構文構文構文

EXECUTE IMMEDIATE dynamic_string

execute_immediate_statement

INTOdefine_variable

,

record_name

RETURNING

RETURNINTO bind_argument

,

;

USING

IN

OUT

IN OUTbind_argument

,

PL/SQL の言語要素 13-65

Page 474: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

bind_argument動的 SQL 文に渡される値を持つ式か、または動的 SQL 文から戻された値を格納する変数です。

define_variable_name選択された列の値を格納する変数を識別します。

dynamic_string1 つの SQL 文または PL/SQL ブロックを表す文字列リテラル、変数または式です。NCHAR型または NVARCHAR2型ではなく、CHAR型または VARCHAR2型である必要があります。

INTO ...単一行の問合せの場合に使用され、取り出された列値を入れる変数またはレコードを指定します。問合せによって取り出された値それぞれに対して、INTO句の中に、対応する型互換性変数が存在している必要があります。

record_name選択された行を格納するユーザー定義のレコードまたは %ROWTYPEレコードを識別します。

RETURNING INTO ...RETURNING句のある(BULK COLLECT句のない)DML 文の場合に使用され、列の値が戻されるバインド変数を指定します。DML 文によって戻された値それぞれに対して、RETURNING INTO句の中に、対応する型互換性変数が存在している必要があります。

USING ...入力または出力バインド引数(あるいはその両方)のリストを指定します。デフォルトのパラメータ・モードは INです。

13-66 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 475: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文

使用上の注意使用上の注意使用上の注意使用上の注意

複数行の問合せの場合を除いて、動的文字列には任意の SQL 文( 後のセミコロンなし)または任意の PL/SQL ブロック( 後のセミコロン付き)を含めることができます。また、バインド引数のプレースホルダも含めることができます。バインド引数を使用してスキーマ・オブジェクトの名前を動的 SQL 文に渡すことはできません。

バインド引数は、すべて USING句に入れることができます。デフォルトのパラメータ・モードは INです。RETURNING句を持つ DML 文の場合は、パラメータ・モード OUTを定義して指定しなくても、OUT引数を RETURNING INTO句に入れることができます。USING句と RETURNING INTO句の両方を使用する場合、USING句には IN引数のみを含めることができます。

実行時に、バインド引数は動的文字列内の対応するプレースホルダを置き換えます。すべてのプレースホルダを USING句内または RETURNING INTO句内(あるいはその両方)のバインド引数に関連付ける必要があります。数値リテラル、文字リテラルおよび文字列リテラルはバインド引数として使用できますが、ブール・リテラル(TRUE、FALSEおよび NULL)は使用できません。動的文字列に NULL を渡すには、回避策を使用する必要があります。7-13ページの「動的 SQL への NULL の引渡し」を参照してください。

動的 SQL はすべての SQL データ型をサポートしています。たとえば、定義変数やバインド引数をコレクション、LOB、オブジェクト型のインスタンスおよび ref とすることができます。動的 SQL は PL/SQL 固有の型をサポートしていません。たとえば、定義変数やバインド引数をブールまたは索引付き表にすることはできません。例外として、PL/SQL レコードを INTO句に入れることができます。

動的 SQL 文は、バインド引数の新しい値を使用して繰り返し実行できます。ただし、EXECUTE IMMEDIATEは実行のたびに動的文字列を準備するため、オーバーヘッドが発生します。

EXECUTE IMMEDIATEコマンドの文字列引数に、NCHAR、NVARCHAR2などの各国語キャラクタ・タイプを使用することはできません。

PL/SQL の言語要素 13-67

Page 476: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXECUTE IMMEDIATE 文

例例例例

次の PL/SQL ブロックには動的 SQL の例がいくつか含まれています。

DECLARE sql_stmt VARCHAR2(200); plsql_block VARCHAR2(500); emp_id NUMBER(4) := 7566; salary NUMBER(7,2); dept_id NUMBER(2) := 50; dept_name VARCHAR2(14) := 'PERSONNEL'; location VARCHAR2(13) := 'DALLAS'; emp_rec emp%ROWTYPE;BEGIN EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)'; sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)'; EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location; sql_stmt := 'SELECT * FROM emp WHERE empno = :id'; EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id; plsql_block := 'BEGIN emp_pkg.raise_salary(:id, :amt); END;'; EXECUTE IMMEDIATE plsql_block USING 7788, 500; sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1 RETURNING sal INTO :2'; EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary; EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num' USING dept_id; EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';END;

関連項目関連項目関連項目関連項目

OPEN-FOR-USING 文

13-68 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 477: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXIT 文

EXIT 文文文文

EXIT文は、ループを終了します。EXIT文には、無条件 EXITと、条件付き EXIT WHENという 2 つの形式があります。どちらの形式でも、終了するループの名前を指定できます。詳細は、4-8 ページの「ループの反復の制御 : LOOP 文と EXIT 文」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

boolean_expressionTRUE、FALSEまたは NULLのいずれかのブール値を戻す式です。この式は、ループが繰り返されるたびに評価されます。式が TRUEを戻す場合、カレント・ループ(またはlabel_nameのラベルの付いたループ)はただちに終了します。boolean_expressionの構文は、13-71 ページの「式」を参照してください。

EXIT無条件の(つまり WHEN句のない)EXIT文は、カレント・ループをただちに終了します。実行はループの直後の文から再開されます。

label_name終了するループを識別します。カレント・ループ、またはラベルが付けられている外側のループのいずれかになります。

使用上の注意使用上の注意使用上の注意使用上の注意

EXIT文は、ループの内側でのみ使用できます。PL/SQL では無限ループをコーディングできます。たとえば、次のループは、通常の方法では永久に終了しません。

WHILE TRUE LOOP ... END LOOP;

このループを終了させるには、EXIT文を使用します。

EXIT文を使用してカーソル FORループを途中で終了させると、カーソルは自動的にクローズされます。ループの内側で例外が呼び出された場合も、カーソルは自動的にクローズされます。

EXITlabel_name WHEN boolean_expression

;

exit_statement

PL/SQL の言語要素 13-69

Page 478: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

EXIT 文

例例例例

次の例にある EXIT文は、ブロックから直接終了できないため誤りです。この文が終了できるのはループからのみです。

DECLARE amount NUMBER; maximum NUMBER;BEGIN ... BEGIN ... IF amount >= maximum THEN EXIT; -- not allowed; use RETURN instead END IF; END;

次のループは本来なら 10 回実行されますが、フェッチする行が 10 行未満の場合は途中で終了します。

FOR i IN 1..10 LOOP FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; total_comm := total_comm + emp_rec.comm;END LOOP;

次の例では、ループ・ラベルの使用方法を示しています。

<<outer>>FOR i IN 1..10 LOOP ... <<inner>> FOR j IN 1..100 LOOP ... EXIT outer WHEN ... -- exits both loops END LOOP inner;END LOOP outer;

関連項目関連項目関連項目関連項目

式、LOOP 文

13-70 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 479: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

式式式式

式は、変数、定数、リテラル、演算子、ファンクション・コールの任意の組合せです。 も単純な式は、1 個の変数で構成されています。

PL/SQL コンパイラは、式を構成する変数、定数、リテラルおよび演算子の型から、式のデータ型を決定します。式が評価されたときは、その型の 1 つの値が結果として得られます。詳細は、2-23 ページの「PL/SQL の式および比較」を参照してください。

構文構文構文構文

(

boolean_expression

character_expression

date_expression

numeric_expression

)

expression

AND

OR

NOT

boolean_constant_name

boolean_function_call

boolean_literal

boolean_variable_name

other_boolean_form

NOT

boolean_constant_name

boolean_function_call

boolean_literal

boolean_variable_name

other_boolean_form

boolean_expression

PL/SQL の言語要素 13-71

Page 480: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

character_constant_name

character_function_call

character_literal

character_variable_name

: host_variable_name: indicator_name

character_expression

||

character_constant_name

character_function_call

character_literal

character_variable_name

: host_variable_name: indicator_name

collection_name . EXISTS ( index )

cursor_name

cursor_variable_name

: host_cursor_variable_name

SQL

%

FOUND

ISOPEN

NOTFOUND

expression

relational_operator expression

ISNOT

NULL

NOT

LIKE pattern

BETWEEN expression AND expression

IN ( expression

,

)

other_boolean_form

13-72 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 481: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

cursor_name

cursor_variable_name

: host_cursor_variable_name

SQL

% ROWCOUNT

SQL % BULK_ROWCOUNT ( index )

: host_variable_name: indicator_name

numeric_constant_name

numeric_function_call

numeric_literal

numeric_variable_name

collection_name .

COUNT

FIRST

LAST

LIMIT

NEXT

PRIOR( index )

** exponent

numeric_subexpression

PL/SQL の言語要素 13-73

Page 482: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

date_constant_name

date_function_call

date_literal

date_variable_name

: host_variable_name: indicator_name

date_expression

+

_numeric_expression

numeric_subexpression

+

*

/

numeric_subexpression

numeric_expression

13-74 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 483: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

BETWEENこの比較演算子は、ある値が指定範囲の中にあるかどうかをテストします。つまり、下限以上、上限以下にあるかどうかがテストされます。

boolean_constant_nameBOOLEAN型の定数を指定します。このような定数は、TRUE、FALSE、または NULLに初期化される必要があります。ブール定数に対する算術演算は許可されていません。

boolean_expressionTRUE、FALSEまたは NULLのいずれかのブール値を戻す式です。

boolean_function_callブール値を戻すファンクション・コールです。

boolean_literal事前定義の値 TRUE、FALSE、または NULL(存在しない値、不明な値または適用できない値を表す)です。データベース列に値 TRUEや FALSEを挿入できません。

boolean_variable_nameBOOLEAN型の変数を識別します。BOOLEAN変数に代入できるのは、値 TRUE、FALSEおよび NULLのみです。列の値を選択またはフェッチして BOOLEAN変数に入れることはできません。BOOLEAN変数に対する算術演算も許可されていません。

%BULK_ROWCOUNTFORALL文で使用するように設計された、暗黙カーソル SQLの複合属性です。詳細は、13-172 ページの「SQL カーソル」を参照してください。

character_constant_name文字値を格納する、事前に宣言された定数を識別します。この定数は、文字値または暗黙的に文字値に変換可能な値に初期化される必要があります。

character_expression文字または文字列を戻す式です。

character_function_call文字値または暗黙的に文字値に変換可能な値を戻すファンクション・コールです。

PL/SQL の言語要素 13-75

Page 484: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

character_literal文字値または暗黙的に文字値に変換可能な値を表すリテラルです。

character_variable_name文字値を格納する、事前に宣言された変数を識別します。

collection_name現行の有効範囲のうち、これより前の部分で宣言されているコレクション(ネストした表、索引付き表または VARRAY)を指定します。

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で事前に宣言されている PL/SQL カーソル変数を識別します。

date_constant_name日付値を格納する、事前に宣言された定数を識別します。この定数は、日付値、または暗黙的に日付値に変換可能な値に初期化される必要があります。

date_expression日付 / 時刻値を戻す式です。

date_function_call日付値、または暗黙的に日付値に変換可能な値を戻すファンクション・コールです。

date_literal日付値、または暗黙的に日付値に変換可能な値を表すリテラルです。

date_variable_name日付値を格納する、事前に宣言された変数を識別します。

EXISTS、、、、COUNT、、、、FIRST、、、、LAST、、、、LIMIT、、、、NEXT、、、、PRIORコレクション・メソッドです。コレクションの名前にこれらを付加すると、有用な情報が戻されます。たとえば、EXISTS(n)は、コレクションに n番目の要素が存在する場合にTRUEを戻します。それ以外の場合、EXISTS(n)は FALSEを戻します。詳細は、13-23ページの「コレクション・メソッド」を参照してください。

13-76 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 485: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

exponent数値を戻す式です。

%FOUND、、、、%ISOPEN、、、、%NOTFOUND、、、、%ROWCOUNTカーソルの属性です。カーソル名またはカーソル変数名にこれらの属性を追加すると、複数行の問合せの実行に関する有用な情報が戻されます。これらの属性は暗黙カーソル SQLにも追加できます。

host_cursor_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数には、接頭辞としてコロンを付ける必要があります。

host_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡される変数を識別します。ホスト変数のデータ型は、適切な PL/SQL のデータ型に暗黙的に変換できる必要があります。また、ホスト変数には、接頭辞としてコロンを付ける必要があります。

INセット・メンバーシップをテストする比較演算子です。集合のいずれかのメンバーと等しいかどうかがテストされます。集合には NULL が含まれていてもかまいませんが、NULL は無視されます。さらに、次の形式の式の場合、

value NOT IN set

集合に NULL が含まれている場合は、FALSEが戻されます。

index戻される値が BINARY_INTEGER型の値、またはその型に暗黙的に変換可能な値になる数値式です。

indicator_namePL/SQL ホスト環境で宣言され、PL/SQL に渡される標識変数を識別します。標識変数には、接頭辞としてコロンを付ける必要があります。標識変数は、関連付けられたホスト変数の値または条件を示します。たとえば、Oracle プリコンパイラ環境では、標識変数を使用して出力ホスト変数内の NULL や切り捨てられた値を検出できます。

IS NULLオペランドが NULL の場合はブール値 TRUEを戻し、オペランドが NULL でない場合はFALSEを戻す比較演算子です。

PL/SQL の言語要素 13-77

Page 486: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LIKE文字値とパターンを比較する比較演算子です。大 / 小文字が区別されます。LIKEは、文字のパターンが一致した場合はブール値 TRUE、一致しない場合は FALSEを戻します。

NOT、、、、AND、、、、OR2-25 ページの表 2-2 の 3 値論理に従う論理演算子です。ANDは、オペランドの両方が TRUEの場合にのみ TRUEを戻します。ORは、オペランドの片方が TRUE ならば TRUEを戻します。NOTはオペランドの反対の値(論理否定)を戻します。詳細は、2-25 ページの「論理演算子」を参照してください。

NULLNULL を表すキーワードです。存在しない値、不明な値または適用できない値を示します。数値式または日付式の中で NULLを使用すると、結果は NULL になります。

numeric_constant_name数値を格納する、事前に宣言された定数を識別します。この定数は、数値または暗黙的に数値に変換可能な値に初期化される必要があります。

numeric_expression整数または実数を戻す式です。

numeric_function_call数値または暗黙的に数値に変換可能な値を戻すファンクション・コールです。

numeric_literal数値または暗黙的に数値に変換可能な値を表すリテラルです。

numeric_variable_name数値を格納する、事前に宣言された変数を識別します。

patternLIKE演算子によって、指定された文字列値と比較される文字列です。pattern には、ワイルドカードと呼ばれる特殊目的の文字を 2 種類使用できます。アンダースコア(_)は 1 つの文字を表し、パーセント記号(%)は 0(ゼロ)個以上の文字を表します。パターンの後にESCAPE 'character_literal'を使用することもできます。文字列の中で、パーセント記号またはアンダースコアの前にエスケープ文字があると、それらはワイルドカードとして認識されません。

13-78 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 487: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

relational_operator式を比較する演算子です。各演算子の意味は、2-26 ページの「比較演算子」を参照してください。

SQLSQL の DML 文を処理するために、Oracle によって暗黙的にオープンされるカーソルを識別します。暗黙カーソル SQLは常に、直前に実行された SQL 文を参照します。

+、、、、-、、、、/、、、、*、、、、**加算、減算、除算、乗算、指数の演算子を示す記号です。

||連結演算子です。次の例に示すように、string1 と string2 を連結した結果は、string1 の後にstring2 が続く文字列になります。

'Good' || ' morning!' = 'Good morning!'

次の例では、NULL は連結の結果に影響しないことを示します。

'suit' || NULL || 'case' = 'suitcase'

長さが 0(ゼロ)の文字列('')は NULL 文字列と呼ばれ、NULL と同じように扱われます。

使用上の注意使用上の注意使用上の注意使用上の注意

ブール式では、互換性のあるデータ型を持つ値のみを比較できます。詳細は、3-23 ページの「PL/SQL データ型の変換」を参照してください。

条件制御文においてブール式が TRUEを戻すと、関連する一連の文が実行されます。ただし、式が FALSEまたは NULLを戻すと、関連する一連の文は実行されません。

関係演算子は、BOOLEAN型のオペランドに適用できます。定義によれば、TRUEは FALSEよりも大きい値を持ちます。NULL の関係する比較は、常に NULL を戻します。ブール式の値はブール変数にしか代入できず、ホスト変数やデータベースの列には代入できません。また、BOOLEAN型からの、または BOOLEAN 型へのデータ型変換はできません。

次の例に示すように、加算演算子または減算演算子を使用すると、日付値を増減できます。

hire_date := '10-MAY-95';hire_date := hire_date + 1; -- makes hire_date '11-MAY-95'hire_date := hire_date - 5; -- makes hire_date '06-MAY-95'

PL/SQL がブール式を評価する場合は、優先順位が も高いのが NOT演算子で、次が AND演算子、 後が OR演算子です。ただし、カッコを使用すると、演算子のデフォルトの優先順位を変更できます。

PL/SQL の言語要素 13-79

Page 488: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

式の中では、事前定義の優先順位に従って演算が実行されます。デフォルトの演算順序を、優先順位の高いものから順に示すと、次のようになります。

カッコ指数単項演算子乗算および除算加算、減算および連結

PL/SQL では、優先順位の等しい演算子を評価する順序は特に決まっていません。ある式の一部にカッコで囲まれた別の式が含まれている場合、PL/SQL では、カッコで囲まれた式を先に評価し、その結果の値を外側の式で使用します。カッコで囲まれた式がネストされている場合、PL/SQL では、 も内側にある式を 1 番目に評価し、 も外側にある式を 後に評価します。

例例例例

式の例を次に示します。

(a + b) > c -- Boolean expressionNOT finished -- Boolean expressionTO_CHAR(acct_no) -- character expression'Fat ' || 'cats' -- character expression'15-NOV-95' -- date expressionMONTHS_BETWEEN(d1, d2) -- date expressionpi * r**2 -- numeric expressionemp_cv%ROWCOUNT -- numeric expression

関連項目関連項目関連項目関連項目

代入文、定数と変数、EXIT 文、IF 文、LOOP 文

13-80 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 489: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FETCH 文

FETCH 文文文文

FETCH文は、複数行の問合せの結果セットから、行データを取り出します。一度に 1 行、複数の行、またはすべての行をフェッチできます。データは問合せが選択した列に対応する変数またはフィールドに格納されます。詳細は、6-11 ページの「PL/SQL を使用したデータの問合せ」を参照してください。

構文構文構文構文

FETCH

cursor_name

cursor_variable_name

: host_cursor_variable_name

fetch_statement

INTOvariable_name

,

record_name

BULK COLLECT INTOcollection_name

: host_array_name

,

LIMIT numeric_expression

;

PL/SQL の言語要素 13-81

Page 490: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FETCH 文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

BULK COLLECTコレクションを PL/SQL エンジンに戻す前にバルク・バインド出力するように、SQL エンジンに指示します。SQL エンジンは、INTOリスト内で参照されるすべてのコレクションをバルク・バインドします。

collection_nameバルク・フェッチした列値を格納するための、宣言されたコレクションを識別します。問合せ select_itemごとに、リストの中に、対応する型互換のコレクションが存在している必要があります。

cursor_name現行の有効範囲の中で宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で宣言されている PL/SQL カーソル変数(またはパラメータ)を識別します。

host_array_nameバルク・フェッチした列値を格納するための配列を識別します。この配列は、PL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されます。問合せ select_itemごとに、リストの中に、対応する型互換の配列が存在している必要があります。ホスト配列には、接頭辞としてコロンが必要です。

host_cursor_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

LIMITバルク(スカラーではない)FETCH文の中でのみ許されるオプションの句です。結果セット全体ではなく、一度にいくつかの行をバルク・フェッチします。

record_nameフェッチした行の値を格納する、ユーザー定義のレコードまたは %ROWTYPEレコードを識別します。カーソルまたはカーソル変数に関連付けられた問合せが戻す列の値に対して、レコードの中に、対応する型互換のフィールドが存在している必要があります。

13-82 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 491: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FETCH 文

variable_nameフェッチした列値を格納するための変数を識別します。カーソルまたはカーソル変数に関連付けられた問合せが戻す列の値に対して、リストの中に、対応する型互換の変数が存在している必要があります。

使用上の注意使用上の注意使用上の注意使用上の注意

複数行の問合せを処理するには、カーソル FORループか FETCH文を使用します。

問合せの WHERE句に含まれる変数は、カーソルまたはカーソル変数がオープンされたときにのみ評価されます。結果セットや問合せの中の変数の値を変更するには、カーソルまたはカーソル変数を、新しい値に設定して再オープンする必要があります。

カーソルを再オープンするには、まずクローズしてください。ただし、カーソル変数を再オープンする場合には、その前にクローズする必要はありません。

同じカーソルまたはカーソル変数を使用した別々のフェッチで、異なる INTOリストを使用できます。個々の FETCH 文で別の行を取り出し、ターゲット変数に値を代入します。

結果セットの中に行が残っていない状態で FETCH文を実行すると、ターゲット・フィールドの値またはターゲット変数の値は予測不能となり、%NOTFOUND属性は TRUEを戻します。

PL/SQL では、カーソル変数の戻り型が、必ず FETCH文の INTO句と互換性を持ちます。カーソル変数に関連付けられた問合せが戻す列の値に対して、INTO句の中に、対応する、型互換性のあるフィールドまたは変数が存在している必要があります。また、フィールドまたは変数の数は、列の値の数と一致する必要があります。

カーソル変数を、そのカーソル変数からフェッチするサブプログラムの仮パラメータとして宣言する場合は、INまたは IN OUTモードを指定する必要があります。ただし、サブプログラムがカーソル変数もオープンする場合は、IN OUTモードを指定する必要があります。

一連の FETCH文では取り出すデータが常に不足するため、FETCH がデータを戻さない場合でも例外は呼び出されません。この状態を検出するには、カーソル属性 %FOUNDまたは%NOTFOUNDを使用する必要があります。

クローズしている、または一度もオープンされていないカーソルまたはカーソル変数からフェッチを実行すると、PL/SQL によって事前定義の例外 INVALID_CURSORが呼び出されます。

PL/SQL の言語要素 13-83

Page 492: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

BULK COLLECT の制限

BULK COLLECT の制限の制限の制限の制限

BULK COLLECT句には、次の制限が適用されます。

� キーが文字列型の結合配列に対しては BULK COLLECT を使用できません。

� BULK COLLECT句はサーバー側(クライアント側ではなく)のプログラムの中でしか使用できません。クライアント側で使用すると、「この機能はクライアント側のプログラムではサポートされていません。」というエラーが表示されます。

� BULK COLLECT INTO句に示されるすべてのターゲット変数は、コレクションである必要があります。

� コンポジット・ターゲット(オブジェクトなど)を RETURNING INTO句で使用することはできません。使用すると、「RETURNING句ではサポートされていない機能です。」というエラーが発生します。

� 暗黙的なデータ型変換が必要な場合、複数のコンポジット・ターゲットを BULK COLLECT INTO句で使用することはできません。

� 暗黙的なデータ型変換が必要な場合、コンポジット・ターゲットのコレクション(オブジェクトのコレクションなど)を BULK COLLECT INTO句で使用することはできません。

例例例例

次の例では、カーソルに対応する問合せの中の変数はカーソルがオープンされたときにのみ評価されることを示します。

DECLARE my_sal NUMBER(7,2); n INTEGER(2) := 2; CURSOR emp_cur IS SELECT n*sal FROM emp;BEGIN OPEN emp_cur; -- n equals 2 here LOOP FETCH emp_cur INTO my_sal; EXIT WHEN emp_cur%NOTFOUND; -- process the data n := n + 1; -- does not affect next FETCH; sal will be multiplied by 2 END LOOP;

次の例では、カーソル変数 emp_cvからユーザー定義のレコード emp_recへ一度に 1 行ずつ行をフェッチします。

DECLARE TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; emp_cv EmpCurTyp;

13-84 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 493: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FETCH 文

emp_rec emp%ROWTYPE;BEGIN LOOP FETCH emp_cv INTO emp_rec; EXIT WHEN emp_cv%NOTFOUND; ... END LOOP;END;

BULK COLLECT句を使用すると、一度に結果セットの列全体または結果セット全体をフェッチできます。次の例では、1 つのカーソルから列を取り出し、1 つのコレクションに代入します。

DECLARE TYPE NameList IS TABLE OF emp.ename%TYPE; names NameList; CURSOR c1 IS SELECT ename FROM emp WHERE job = 'CLERK';BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO names; ... CLOSE c1;END;

次の例では、LIMIT句を使用します。ループが繰り返されるたびに、FETCH文によって 100(またはそれ以下の)行が索引付き表 acct_idsにフェッチされます。前の値は上書きされます。

DECLARE TYPE NumList IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; CURSOR c1 IS SELECT acct_id FROM accounts; acct_ids NumList; rows NATURAL := 100; -- set limitBEGIN OPEN c1; LOOP /* The following statement fetches 100 rows (or less). */ FETCH c1 BULK COLLECT INTO acct_ids LIMIT rows; EXIT WHEN c1%NOTFOUND; ... END LOOP; CLOSE c1;END;

関連項目関連項目関連項目関連項目

CLOSE 文、カーソル、カーソル変数、LOOP 文、OPEN 文、OPEN-FOR 文

PL/SQL の言語要素 13-85

Page 494: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FORALL 文

FORALL 文文文文

FORALL文は、一連の INSERT、UPDATEまたは DELETE文を発行します。通常、FORループを使用する場合より高速に処理を実行できます。この文には、いくつかの設定コードが必要です。これは、ループが繰り返されるたびに、VALUES句または WHERE句内の 1 つ以上のコレクションの値が使用されるためです。詳細は、11-9 ページの「DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)」を参照してください。

構文構文構文構文

bounds_clause

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

INDICES OF collection_name索引変数の値が指定したコレクション要素の添字に対応するように指定する句です。この句を使用すると、いくつかの要素が削除されたネストした表、または数値の添字を持つ結合配列で、FORALLを使用できます。

BETWEEN lower_bound AND upper_boundINDICES OF句の添字の範囲を制限します。範囲内の添字がコレクションに存在しない場合、その添字はスキップされます。

FORALL index_name IN bounds_clause sql_statementSAVE EXCEPTIONS

;

lower_bound .. upper_bound

INDICES OF collectionBETWEEN lower_bound AND upper_bound

VALUES OF index_collection

13-86 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 495: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FORALL 文

VALUES OF index_collection_nameFORALL索引変数の添字に、index_collection_nameで指定した別のコレクションの要素の値が使用されるように指定する句です。ここで使用する別のコレクションは、ポインタのセットとして機能します。index_collection_nameで指定する要素に応じて、FORALLは任意の順序で添字に対する反復処理を実行できます(同じ添字を複数回使用することもできます)。

索引コレクションは、ネストした表であるか、または PLS_INTEGERか BINARY_INTEGERによって索引付けされ、要素も PLS_INTEGERか BINARY_INTEGERである結合配列である必要があります。索引コレクションが空の場合、例外が呼び出され、FORALL 文は実行されません。

index_nameコレクションの添字として、FORALL文の中でのみ参照できる、未宣言の識別子です。

index_nameの暗黙的な宣言は、ループの外側での宣言をオーバーライドします。文の中では同じ名前の別の変数を参照できません。FORALL文の中では、index_nameは式に使用したり値を代入できません。

lower_bound .. upper_bound連続した索引番号の有効範囲を指定する数式です。必要に応じて、PL/SQL はこれらの番号を も近い整数に四捨五入します。SQL エンジンは、範囲内の各索引番号に対して一度ずつSQL 文を実行します。この式は、FORALL文を入力すると、一度評価されます。

SAVE EXCEPTIONS一部の DML 操作が失敗しても FORALLループを継続させるオプションのキーワードです。プログラムでは、例外をただちに呼び出すのではなく、FORALL文の終了後に例外を 1 つ呼び出します。エラーの詳細は、SQL%BULK_EXCEPTIONSでループの後に取得できます。プログラムでは、発生するたびに例外を個別に処理するのではなく、FORALLループの後ですべてのエラーをレポートまたはクリーンアップできます。

sql_statementVALUES句または WHERE句内のコレクション要素を参照する INSERT文、UPDATE文またはDELETE文です。

PL/SQL の言語要素 13-87

Page 496: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FORALL 文

使用上の注意使用上の注意使用上の注意使用上の注意

SQL 文は複数のコレクションを参照できますが、パフォーマンス上のメリットは、添字付きコレクションにのみ適用されます。

FORALL文が失敗すると、データベースの変更は、各 SQL 文の実行の前にマークされた暗黙的なセーブポイントまでロールバックされます。前回の FORALLループの反復中に行われた変更はロールバックされません。

制限制限制限制限

FORALL文には、次の制限が適用されます。

� キーが文字列型の結合配列の要素は、ループできません。

� FORALLループ内では、UPDATE文の SET句と WHERE句の両方で、同じコレクションを参照することはできません。この場合は、そのコレクションの 2 つ目のコピーを作成し、WHERE句では新しい名前を参照する必要があります。

� FORALL文を使用できるのは、クライアント側ではなく、サーバー側のプログラム内のみです。

� INSERT文、UPDATE文または DELETE文では少なくとも 1 つのコレクションを参照する必要があります。たとえば、ループで一連の定数値を挿入する FORALL文では、例外が呼び出されます。

� 明示的な範囲を指定する場合は、その範囲内のすべてのコレクション要素が存在している必要があります。要素が存在しなかったり削除されていた場合は、エラーが発生します。

� INDICES OF句または VALUES OF句を使用する場合、DML 文で参照されるすべてのコレクションの添字が、索引変数の値と一致している必要があります。DELETE、EXTENDなどの操作は、どのコレクションも同じ添字のセットを持つように、すべてのコレクションに適用してください。参照されている要素がいずれかのコレクション内に存在しない場合は、エラーが発生します。SAVE EXCEPTIONS句を使用している場合、このエラーは他のエラーと同じように扱われ、FORALL文は停止されません。

� FORALL文によってコールされる DML 文内のレコード・フィールドを個別に参照することはできません。かわりに、UPDATE文の SET ROW句か、または INSERT文のVALUES句でレコード全体を指定できます。

� コレクションの添字は式(i+1など)ではなく、索引変数(iなど)である必要があります。

� カーソル属性 %BULK_ROWCOUNTは、他のコレクションに代入したり、パラメータとしてサブプログラムに渡すことはできません。

13-88 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 497: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

FORALL 文

例例例例

上限と下限を使用して、コレクションの任意のスライスをバルク・バインドできます。

DECLARE TYPE NumList IS VARRAY(15) OF NUMBER; depts NumList := NumList();BEGIN -- fill varray here ... FORALL j IN 6..10 -- bulk-bind middle third of varray UPDATE emp SET sal = sal * 1.10 WHERE deptno = depts(j);END;

バルク・バインドは、添字付きコレクションにのみ適用されます。次の例では、medianファンクションに渡されるコレクション salsはバルク・バインドされません。

FORALL i IN 1..20 INSERT INTO emp2 VALUES (enums(i), names(i), median(sals), ...);

関連項目関連項目関連項目関連項目

11-19 ページの「BULK COLLECT 句を使用した、問合せ結果のコレクションへの取出し」

PL/SQL の言語要素 13-89

Page 498: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ファンクション

ファンクションファンクションファンクションファンクション

ファンクションとは、パラメータを指定して単一の値を戻すことができるサブプログラムのことです。ファンクションには、仕様部と本体の 2 つの部分があります。ファンクションの仕様部はキーワード FUNCTIONで始め、戻り値のデータ型を指定する RETURN句で終わります。パラメータ宣言はオプションです。パラメータを取らないファンクションではカッコを書きません。ファンクション本体は、キーワード IS(または AS)で始め、キーワードENDで終わります。END の後には、オプションとしてファンクション名を続けることができます。

ファンクション本体には、宣言部(オプション)、実行部、例外処理部(オプション)の 3つの部分があります。宣言部には、型、カーソル、定数、変数、例外およびサブプログラムが含まれています。これらの項目はローカルで、ファンクションを終了すると消去されます。実行部には、値の代入、実行の制御およびデータの操作を実行する文があります。例外処理部には、実行の途中で呼び出された例外を処理する例外ハンドラがあります。詳細は、8-4 ページの「PL/SQL ファンクション」を参照してください。

構文構文構文構文

ffunction_declaration | function body

FUNCTION function_name( parameter_declaration

,

)RETURN datatype ;

function_spec

CREATEOR REPLACE

FUNCTION function_name

( parameter_declaration

,

)RETURN datatype

AUTHIDCURRENT_USER

DEFINER PARALLEL_ENABLE DETERMINISTIC IS

AS

13-90 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 499: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ファンクション

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

AUTHIDストアド・ファンクションをその所有者(デフォルト)と現行ユーザーのどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が所有者と現行ユーザーのどちらのスキーマで解決されるかを決定します。AUTHID CURRENT_USERを指定すると、デフォルトの動作を変更できます。詳細は、8-20 ページの「実行者権限と定義者権限の使用

(AUTHID 句)」を参照してください。

CREATEスタンドアロン・ファンクションを作成するオプションの CREATE句です。これは Oracleデータベースに格納できます。CREATE文は、SQL*Plus またはシステム固有の動的 SQL を使用したプログラムから対話形式で実行できます。

datatype型指定子です。datatypeの構文は、13-39 ページの「定数と変数」を参照してください。

EXCEPTION exception_handlerEND

function_name;

parameter_name

IN

OUT

IN OUT

NOCOPY

datatype

parameter_declaration

:=

DEFAULTexpression

type_definition

item_declaration

function_declaration

procedure_declarationBEGIN statement

PRAGMA AUTONOMOUS_TRANSACTION ;

PL/SQL の言語要素 13-91

Page 500: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ファンクション

DETERMINISTICオプティマイザが冗長なファンクション・コールを回避するために役立つヒントです。ストアド・ファンクションが同じ引数で事前にコールされた場合は、オプティマイザは前の結果を使用できます。ファンクションの結果をセッション変数の状態またはスキーマ・オブジェクトに依存させないでください。さもないと、コールごとに結果が異なる可能性があります。DETERMINISTICファンクションのみが、ファンクションベースの索引またはクエリー・リライトを使用可能にしたマテリアライズド・ビューからコールできます。詳細は、

『Oracle Database SQL リファレンス』の「CREATE INDEX」および「CREATE MATERIALIZED VIEW」の各文を参照してください。

exception_handler例外ハンドラです。例外が呼び出されると、その例外に関連付けられた一連の文を実行します。exception_handlerの構文は、13-62 ページの「例外」を参照してください。

expression変数、定数、リテラル、演算子、ファンクション・コールの任意の組合せです。 も単純な式は、1 個の変数で構成されています。宣言が PL/SQL コンパイラによって処理されるときに、expressionの値がパラメータに代入されます。その値とパラメータのデータ型には互換性が必要です。

function_nameファンクションに選択する名前を指定します。

IN、、、、OUT、、、、IN OUT仮パラメータの動作を定義するパラメータ・モードです。INパラメータは、コールされるサブプログラムに値を渡します。OUTパラメータは、サブプログラムのコール元に値を戻します。IN OUTパラメータは、コール先のサブプログラムに初期値を渡し、更新された値をコール元に戻します。

item_declarationプログラム・オブジェクトを宣言します。構文は、13-11 ページの「ブロック」を参照してください。

NOCOPYコンパイラ・ヒント(ディレクティブではなく)です。これによって、PL/SQL コンパイラは OUTおよび IN OUTパラメータを、デフォルトの値方式ではなく、参照方式で渡すことができます。このファンクションは、これらのパラメータの一時コピーを作成する必要がないため、高速で実行できます。ただし、ファンクションが未処理例外を戻して終了すると、結果が異なる場合があります。詳細は、8-12 ページの「サブプログラムのパラメータのデフォルト値の使用」を参照してください。

13-92 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 501: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ファンクション

PARALLEL_ENABLEストアド・ファンクションがパラレル DML 評価のスレーブ・セッションで安全に使用されることを宣言します。メイン(ログオン)・セッションの状態が、スレーブ・セッションと共有されることはありません。スレーブ・セッションごとに固有の状態があり、セッション開始時に初期化されます。ファンクションの結果がセッション(static)変数の状態に依存しないようにしてください。さもないと、セッションごとに結果が異なる可能性があります。

parameter_name仮パラメータを識別します。仮パラメータとは、ファンクションの仕様部で宣言され、ファンクション本体の中で参照される変数のことです。

AUTONOMOUS_TRANSACTION プラグマプラグマプラグマプラグマ

ファンクションを自律型としてマークします。自律型トランザクションは、メイン・トランザクションによって開始される独立したトランザクションです。自律型トランザクションを使用すると、メイン・トランザクションを停止し、SQL 操作を実行してその操作をコミットまたはロールバックしてから、メイン・トランザクションを再開できます。詳細は、6-45ページの「自律型トランザクションによる独立した作業単位の実行」を参照してください。

procedure_declarationプロシージャを宣言します。procedure_declarationの構文は、13-138 ページの「プロシージャ」を参照してください。

RETURNRETURN句の開始を知らせるキーワードです。この句では、戻り値のデータ型を定義します。

type_definitionユーザー定義のデータ型を指定します。構文は、13-11 ページの「ブロック」を参照してください。

:= | DEFAULTINパラメータをデフォルト値に初期化します。

PL/SQL の言語要素 13-93

Page 502: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ファンクション

使用上の注意使用上の注意使用上の注意使用上の注意

ファンクションは、式の一部としてコールされます。

promotable := sal_ok(new_sal, new_title) AND (rating > 3);

ストアド・ファンクションは、副作用を制御する特定の規則に従っている場合にのみ、SQL文からコールできます。8-29 ページの「PL/SQL サブプログラムの副作用の制御」を参照してください。

ファンクションには、RETURN文へ導く少なくとも 1 つの実行パスが必要です。実行パスがない場合は、実行時に「ファンクションが値なしで戻されました」というエラーが発生します。RETURN文には、RETURN文の実行時に評価される式が含まれている必要があります。結果として得られる値がファンクション識別子に代入されます。ファンクション識別子は変数のように取り扱われます。

ファンクションの仕様部と本体を合わせて 1 つの単位として作成できます。また、ファンクションの仕様部と本体を別々にすることもできます。このように、ファンクションをパッケージに入れると、実装上の細部を隠ぺいできます。パッケージ仕様部でファンクション仕様部を宣言せずに、パッケージ本体でファンクションを定義できます。ただし、このようなファンクションは、パッケージの中からのみコールできます。

ファンクションの中では、INパラメータは定数のように取り扱われるため、値は代入できません。OUTパラメータはローカル変数のように取り扱われるため、値を変更して参照できます。IN OUTパラメータは初期化された変数のように取り扱われるため、値を代入したり、その値を他の変数に代入できます。パラメータ・モードの詳細は、8-11 ページの表 8-1 を参照してください。

ファンクションでは、OUTモードと IN OUTモードを使用しないでください。ファンクションの目的は、0(ゼロ)個以上のパラメータを取り、単一の値を戻すことです。サブプログラム専用ではない変数の値を変更するという副作用も避ける必要があります。

例例例例

次のファンクションでは、指定された銀行口座の残高を戻します。

FUNCTION balance (acct_id INTEGER) RETURN REAL IS acct_bal REAL;BEGIN SELECT bal INTO acct_bal FROM accts WHERE acctno = acct_id; RETURN acct_bal;END balance;

関連項目関連項目関連項目関連項目

コレクション・メソッド、パッケージ、プロシージャ

13-94 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 503: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

GOTO 文

GOTO 文文文文

GOTO文は、文ラベルまたはブロック・ラベルに無条件に分岐します。ラベルは有効範囲の中で他と重複しないもので、実行可能文か PL/SQL ブロックの前に置かれている必要があります。GOTO文によって、制御はラベルの付いた文またはブロックに移ります。詳細は、4-16 ページの「GOTO 文の使用」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

label_name実行可能文または PL/SQL ブロックに付けるラベル名です。GOTO文を使用すると、<<label_name>>の後に指定した文またはブロックに制御を移すことができます。

使用上の注意使用上の注意使用上の注意使用上の注意

GOTO文の宛先として使用できないものがあります。特に、GOTO文は IF文、LOOP文またはサブブロックには分岐できません。

GOTO文では、カレント・ブロックから同じブロックの別の場所、または囲みブロックには分岐できますが、例外ハンドラには分岐できません。例外ハンドラの GOTO文は、囲みブロックには分岐できますが、カレント・ブロックには分岐できません。

GOTO文を使用してカーソル FORループを途中で終了させると、カーソルは自動的にクローズされます。ループの内側で例外が呼び出された場合も、カーソルは自動的にクローズされます。

ある 1 つのブロックの中では、1 つのラベルは一度のみ使用できます。ただし、囲みブロックやサブブロックなどの他のブロックでそのラベルを使用できます。ターゲット・ラベルがカレント・ブロックにない場合、GOTO文は囲みブロックのうちそのラベルが存在する 初のものに分岐します。

<< label_name >>

label_declaration

GOTO label_name ;

goto_statement

PL/SQL の言語要素 13-95

Page 504: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

GOTO 文

例例例例

どのキーワードにも GOTO文のラベルを付けられるわけではありません。GOTO 文のラベルは、実行可能文か PL/SQL ブロックの前に付けてください。実行可能文のない場所へ分岐するには、NULL文を追加します。

FOR ctr IN 1..50 LOOP DELETE FROM emp WHERE ... IF SQL%FOUND THEN GOTO end_loop; END IF; ...<<end_loop>>NULL; -- an executable statement that specifies inactionEND LOOP;

13-96 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 505: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

IF 文

IF 文文文文

IF文を使用すると、ブール式の値に応じて、一連の文を実行するか、またはスキップできます。詳細は、4-2 ページの「条件テスト : IF 文および CASE 文」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

boolean_expressionTRUE、FALSEまたは NULLのいずれかのブール値を戻す式です。たとえば、等価、以上、未満などの比較があります。THEN キーワードに続く一連の文は、式が TRUEを戻した場合にのみ実行されます。

ELSE制御がこのキーワードに達すると、その直後の一連の文が実行されます。以前の条件テストがいずれも TRUEを戻さなかった場合に発生します。

ELSIF以前の条件がいずれも TRUEを戻さなかった場合に評価されるブール式の開始を知らせます。

THEN式が TRUEを戻した場合、THEN キーワードの後の文が実行されます。

IF boolean_expression THEN statement

if_statement

ELSIF boolean_expression THEN statement

ELSE statementEND IF ;

PL/SQL の言語要素 13-97

Page 506: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

IF 文

使用上の注意使用上の注意使用上の注意使用上の注意IF文には、IF-THEN、IF-THEN-ELSEおよび IF-THEN-ELSIFの 3 つの形式があります。IF文の も単純な形式では、ブール式を、キーワード THENと END IFで囲まれた一連の文に関連付けます。一連の文は、式が TRUEを戻す場合にのみ実行されます。式が FALSEまたは NULLを戻す場合、IF文は何も実行しません。いずれの場合も、制御は次の文に渡されます。

IF文の 2 つ目の形式では、キーワード ELSEが追加され、その後に一連の代替文を続けます。ブール式が FALSEまたは NULLを戻す場合にのみ、ELSE句内の一連の文が実行されます。このように、ELSE句では必ず一連の文が実行されます。

IF文の 3 つ目の形式では、キーワード ELSIFを使用して別のブール式を追加します。 初の式が FALSEまたは NULLを戻す場合、ELSIF句は別の式を評価します。IF文は任意の数の ELSIF句を持つことができます。 後の ELSE句はオプションです。ブール式は上から下に 1 つずつ評価されます。いずれかの式が TRUEを戻す場合は、それに関連する一連の文が実行され、制御は次の文に移ります。すべての式が FALSEまたは NULLを戻す場合は、ELSE句内の一連の文が実行されます。

一連の文が 1 つでも実行されると、IF文の処理は終了します。このため、一連の文が複数回実行されることはありません。ただし、THEN句と ELSE句には、さらに IF文を入れることができます。つまり、IF文はネストできます。

例例例例次の例では、shoe_countの値が 10 の場合、1 番目と 2 番目のブール式はどちらも TRUEを戻します。ただし、1 つの式が TRUEを戻し、それに関連する一連の文が実行された時点で IF文の処理は終了するため、order_quantityには正しい値 50 が代入されます。ELSIFに関連付けられた式は評価されず、制御は INSERT文に移ります。

IF shoe_count < 20 THEN order_quantity := 50;ELSIF shoe_count < 30 THEN order_quantity := 20;ELSE order_quantity := 10;END IF;

INSERT INTO purchase_order VALUES (shoe_type, order_quantity);

次の例では、scoreの値に応じて、2 つの状態メッセージのどちらかを grades表に挿入します。

IF score < 70 THEN fail := fail + 1; INSERT INTO grades VALUES (student_id, 'Failed');ELSE pass := pass + 1; INSERT INTO grades VALUES (student_id, 'Passed');END IF;

関連項目関連項目関連項目関連項目

CASE 文、式

13-98 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 507: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

INSERT 文

INSERT 文文文文

INSERT文は、データベース表に 1 つ以上の新しい行データを追加します。INSERT文の詳細は、『Oracle Database SQL リファレンス』を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

alias参照される表またはビューの別名(通常は短縮名)です。

column_name[, column_name]...データベースの表またはビューの列のリストを識別します。VALUES句の式が同じ順序でリストに示されているかぎり、列はどのような順序で指定してもかまいません。各列の名前はリストの中で一度のみ指定できます。表の列のうち、リストに含まれていないものがある場合、それらの列はそれぞれ NULL、または CREATE TABLE文で指定されたデフォルト値に設定されます。

insert_statement

( column_name

,

)

INSERT INTO ( subquery

TABLE ( subquery2 )

aliastable_reference

)

VALUES ( sql_expression

,

)returning_clause

subquery3;

PL/SQL の言語要素 13-99

Page 508: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

INSERT 文

returning_clause挿入された行から値を戻します。そのため、後で行を SELECTで選択する必要がありません。取り出した列値は、変数またはコレクションに代入できます。RETURNING句はリモートまたはパラレルでの挿入には使用できません。文を実行しても行に影響がない場合、RETURNING句で指定した変数の値は未定義になります。returning_clauseの構文は、13-57 ページの「DELETE 文」を参照してください。

sql_expression任意の有効な SQL の式です。たとえば、リテラル、PL/SQL 変数、単一の値を戻す SQL 問合せなどがあります。詳細は、『Oracle Database SQL リファレンス』を参照してください。PL/SQL では、ここでレコード変数も使用できます。

subquery処理する行セットを提供する SELECT文です。構文は select_into_statementの構文と似ていますが、INTO句は使用できません。13-162 ページの「SELECT INTO 文」を参照してください。

subquery3行セットを戻す SELECT文です。この SELECT 文によって戻された各行が、表に挿入されます。この副問合せは、列リストのすべての列について値を戻す必要があります。また、列リストが存在しない場合は、表の中のすべての列について値を戻す必要があります。

table_reference表またはビューを指定します。指定された表またはビューは、INSERT文の実行時にアクセスできる必要があり、ユーザーは INSERT権限を持つ必要があります。table_referenceの構文は、13-57 ページの「DELETE 文」を参照してください。

TABLE (subquery2)TABLEのオペランドは、1 つの列値を戻す SELECT文です。これはネストした表を表します。この演算子は、値がスカラー値ではなくコレクションになるように指定します。

VALUES (...)式の値を、列リストの中の対応する列に代入します。列リストが指定されていない場合、初の値は CREATE TABLE文で定義された 初の列に、2 番目の値は 2 番目の列に、というように挿入されます。列リストの中では、各列につき指定できる値は 1 つです。挿入される値のデータ型は、列リストの対応する列のデータ型との互換性が必要です。

13-100 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 509: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

INSERT 文

使用上の注意使用上の注意使用上の注意使用上の注意

VALUESリストの中の文字リテラルと日付リテラルは、引用符(')で囲む必要があります。数値リテラルは引用符で囲みません。

暗黙的な SQLカーソルとカーソル属性 %NOTFOUND、%FOUND、%ROWCOUNTおよび%ISOPENを使用すると、INSERT文の実行に関する有用な情報にアクセスできます。

例例例例

次の例では、様々な形式の INSERT文を示します。

INSERT INTO bonus SELECT ename, job, sal, comm FROM emp WHERE comm > sal * 0.25;...INSERT INTO emp (empno, ename, job, sal, comm, deptno) VALUES (4160, 'STURDEVIN', 'SECURITY GUARD', 2045, NULL, 30);...INSERT INTO dept VALUES (my_deptno, UPPER(my_dname), 'CHICAGO');

関連項目関連項目関連項目関連項目

DELETE 文、SELECT INTO 文、UPDATE 文

PL/SQL の言語要素 13-101

Page 510: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

リテラル

リテラルリテラルリテラルリテラル

リテラルは、識別子によって表現する必要がない明示的な数値、文字、文字列またはブール値です。たとえば、数値リテラル 135 や文字列リテラル 'hello world'などです。詳細は、2-6 ページの「リテラル」を参照してください。

構文構文構文構文

+

_integer

real_number

numeric_literal

digit

integer

integer

. integer

.

. integer

E

e

+

_

integer

real_number

’ character ’

’ ’

character_literal

’ character ’

’ ’

string_literal

13-102 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 511: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

リテラル

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

characterPL/SQL キャラクタ・セットのメンバーです。詳細は、2-2 ページの「キャラクタ・セット」を参照してください。

digit数字 0 ~ 9 のうちのいずれかです。

TRUE、、、、FALSE、、、、NULL事前定義のブール値です。

使用上の注意使用上の注意使用上の注意使用上の注意

算術式では、整数と実数の 2 種類の数値リテラルを使用できます。数値リテラルは、句読点文字で区切る必要があります。句読点以外に空白も使用できます。

文字リテラルは引用符(アポストロフィ)で囲まれた 1 文字のことです。文字リテラルには、PL/SQL キャラクタ・セットのすべての印刷可能文字(英字、数字、空白および特殊記号)を使用できます。

文字リテラルの中で、PL/SQL は大 / 小文字を区別します。たとえば、PL/SQL はリテラル'Q'と 'q'を異なるものとみなします。

文字列リテラルは、引用符(')で囲まれた 0(ゼロ)個以上の文字の並びです。NULL 文字列('')は 0(ゼロ)個の文字です。文字列リテラルは 大 32,767 個の文字を保持できます。

文字列の中でアポストロフィを表現する場合は、引用符(')を 1 つではなく、2 つ入力します。引用符を 2 つ入力すると不都合があるか、またはわかりにくくなるリテラルでは、q'esc_char ... esc_char'という表記法を使用して、エスケープ文字を指定できます。このエスケープ文字は、その文字列の他の箇所では使用されていない必要があります。

文字列リテラルの中で、PL/SQL は大 / 小文字を区別します。たとえば、PL/SQL はリテラル 'white'と 'White'を異なるものとみなします。

TRUE

FALSE

NULL

boolean_literal

PL/SQL の言語要素 13-103

Page 512: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

リテラル

文字列リテラルの中では、値に後続する空白が意味を持ちます。つまり、'abc'と 'abc 'は異なります。文字列リテラルの中の後続する空白は、PL/SQL の処理中には切り捨てられませんが、表の CHAR型の列にその値を挿入すると切り捨てられます。

ブール値 TRUEおよび FALSEはデータベース列に挿入できません。

例例例例

次に数値リテラルの例を示します。

25 6.34 7E2 25e-03 .1 1. +17 -4.4 -4.5D -4.6F

次に文字リテラルの例を示します。

'H' '&' ' ' '9' ']' 'g'

次に文字列リテラルの例を示します。

'$5,000''02-AUG-87''Don''t leave until you''re ready and I''m ready.'q'#Don't leave until you're ready and I'm ready.#'

関連項目関連項目関連項目関連項目

定数と変数、式

13-104 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 513: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOCK TABLE 文

LOCK TABLE 文文文文

LOCK TABLE文は、データベース表全体を指定のロック・モードでロックします。これによって、表の整合性を維持したまま、表アクセスの共有や拒否ができます。詳細は、6-44ページの「LOCK TABLE の使用」を参照してください。

Oracle には、複数のプログラムで、一貫性のあるデータのビューを個別に参照してデータの読取りと書込みを同時に実行できる様々な自動機能が備わっています。そのため、ほとんどの場合、ユーザーが表をロックする必要はありません。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

table_referenceロックする対象の表またはビューです。LOCK TABLE文を実行する場合は、この表またはビューがアクセス可能である必要があります。table_referenceの構文は、13-57 ページの「DELETE 文」を参照してください。

lock_modeロックのタイプを指定します。これは、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVEのいずれかです。

NOWAITこれはオプションのキーワードであり、これを指定すると Oracle は他のユーザーが表をロックしていると待機しません。制御はただちにプログラムに戻されるため、他の処理を実行してから、改めてロックを試みてください。

LOCK TABLE table_reference

,

IN lock_mode MODENOWAIT

;

lock_table_statement

PL/SQL の言語要素 13-105

Page 514: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOCK TABLE 文

使用上の注意使用上の注意使用上の注意使用上の注意

キーワード NOWAITを省略すると、Oracle は表が利用できるようになるまで待ちます。待機時間に制限はありません。表ロックは、トランザクションがコミットまたはロールバックを発行したときに解除されます。

表がロックされていても、他のユーザーは表に対して問合せできますが、問合せを実行しても表のロックを取得できません。

プログラムに SQL ロッキング文が含まれている場合は、ロックを要求している Oracle ユーザーが、ロックのために必要な権限を持っていることを確認してください。DBA は、任意の表をロックできます。他のユーザーは、自分が所有する表か、SELECT、INSERT、UPDATE、DELETEなどの権限が付与されている表をロックできます。

例例例例

次の文は、表 acctsを共有モードでロックします。

LOCK TABLE accts IN SHARE MODE;

関連項目関連項目関連項目関連項目

COMMIT 文、ROLLBACK 文

13-106 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 515: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

LOOP 文文文文

LOOP文は一連の文を複数回実行します。LOOP キーワードと END LOOP キーワードで文を囲みます。PL/SQL では、基本ループ、WHILEループ、FORループ、カーソル FORループの 4 種類がサポートされています。使用方法は、4-8 ページの「ループの反復の制御 : LOOP 文と EXIT 文」を参照してください。

構文構文構文構文

<< label_name >>LOOP statement END LOOP

label_name;

basic_loop_statement

<< label_name >>WHILE boolean_expression

while_loop_statement

<< label_name >>FOR index_name IN

for_loop_statement

REVERSElower_bound .. upper_bound

LOOP statement END LOOPlabel_name

;

LOOP statement END LOOPlabel_name

;

PL/SQL の言語要素 13-107

Page 516: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

basic_loop_statement回数の制限なしに実行するループです。LOOPキーワードと END LOOPキーワードで一連の文を囲みます。ループが繰り返されるたびに一連の文が実行され、制御がループの先頭に戻ります。EXIT、GOTOまたは RAISE文は、ループの外に分岐します。例外が呼び出された場合もループは終了します。

boolean_expressionTRUE、FALSEまたは NULLのいずれかのブール値を戻す式です。式が TRUEを戻す場合にのみ実行される一連の文が関連付けられています。boolean_expressionの構文は、13-71 ページの「式」を参照してください。

cursor_for_loop_statementSQL 問合せを発行し、結果セットの行をループします。この手法を使用すると、問合せの処理が、他のプログラミング言語でテキスト行を読み取る場合と同様に簡単になります。

カーソル FORループは、ループ索引を %ROWTYPE属性のレコードとして暗黙的に宣言し、カーソルをオープンして、結果セットから行の値をフェッチしてレコード内のフィールドに入れる一連の作業を繰り返し、すべての行を処理した後にカーソルをクローズします。

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。カーソル FORループに入ると、cursor_nameは、OPEN文または外側のカーソル FORループによって、すでにオープンされたカーソルを参照できません。

<< label_name >>FOR record_name IN

cursor_for_loop_statement

cursor_name( cursor_parameter_name

,

)

( select_statement )

LOOP statement END LOOPlabel_name

;

13-108 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 517: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

cursor_parameter_nameカーソルの仮パラメータとして宣言された変数を識別します。

(cursor_parameter_declarationの構文は、13-53 ページの「カーソル」を参照してください。)カーソルのパラメータは、問合せの中で定数が使用できる場所であれば、どこででも使用できます。カーソルの仮パラメータは INパラメータにしてください。

for_loop_statement数値 FORループは、指定された整数の範囲内でループを繰り返し実行します。繰返しの範囲は、キーワード FORと LOOPに囲まれた反復スキームの一部です。

繰返しの範囲は FORループに入った段階で評価され、それ以降は評価されません。ループ本体は、lower_bound..upper_boundによって定義された範囲の整数 1 つにつき 1 回実行されます。1 回の繰返しが終わると、ループ索引に増分が加えられます。

index_nameループ索引に名前を付ける未宣言の識別子です(ループ・カウンタと呼ばれる場合もあります)。有効範囲はループ自体になるため、ループの外側では索引を参照できません。

index_nameの暗黙的な宣言は、ループの外側での宣言をオーバーライドします。同じ名前の別の変数を参照するには、次のようにラベルを使用します。

<<main>>DECLARE num NUMBER;BEGIN ... FOR num IN 1..10 LOOP IF main.num > 5 THEN -- refers to the variable num, ... -- not to the loop index END IF; END LOOP;END main;

ループの内側では、索引は定数のように扱われるため、式の中で使用できます。ただし、値は代入できません。

label_nameオプションとしてループに付けるラベル名で、未宣言の識別子です。使用する場合は、二重の山カッコで囲み、ループの先頭に置く必要があります。オプションとして、label_nameを、山カッコで囲まずにループの 後に置くこともできます。

label_nameを EXIT文の中で使用すると、label_nameによってラベル付けされているループを終了できます。カレント・ループのみでなく、外側のループも終了できます。

PL/SQL の言語要素 13-109

Page 518: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

外側の FORループと、その内側のネストされた FORループの索引が同じ名前である場合、ネストされたループから外側のループの索引を参照できません。ただし、外側のループがlabel_nameでラベル付けされている場合は、次のようにドット表記法を使用すれば参照できます。

label_name.index_name

次の例では、外側のループとネストされたループで使用されている同じ名前の 2 つのループ索引を比較しています。

<<outer>>FOR ctr IN 1..20 LOOP ... <<inner>> FOR ctr IN 1..10 LOOP IF outer.ctr > ctr THEN ... END LOOP inner;END LOOP outer;

lower_bound .. upper_bound数値を戻す式です。(それ以外の場合、PL/SQL は事前定義の例外 VALUE_ERRORを呼び出します。)式は、 初にループに入ったときにのみ評価されます。次の例に示すように、下限は 1 である必要はありません。ループ・カウンタの増分値(または減分値)は 1 である必要があります。

FOR i IN -5..10 LOOP ...END LOOP;

内部的に、PL/SQL は PLS_INTEGER一時変数に境界の値を代入します。さらに、必要に応じてその値を も近い整数に四捨五入します。PLS_INTEGERの大きさの範囲は、+/- 2**31です。範囲外の数値を評価した場合、PL/SQL が代入をすると、数値オーバーフローのエラーが発生します。

デフォルトでは、ループ索引には lower_boundの値が代入されます。この値がupper_boundの値を超えていない場合、ループの中の一連の文が実行され、索引が増分されます。索引の値が upper_boundの値を超えていない場合、一連の文がもう一度実行されます。この処理は、索引の値が upper_boundの値を超えるまで繰り返されます。超えた時点で、ループが終了します。

record_name暗黙的に宣言されたレコードを識別します。このレコードは cursor_nameまたはselect_statementによって取り出された行と同じ構造を持ちます。

13-110 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 519: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

レコードはループの内側のみで定義されています。ループの外側からこのレコードのフィールドを参照できません。record_nameの暗黙的な宣言は、ループの外側での宣言をオーバーライドします。同じ名前のレコードは、ブロック・ラベルを使用して参照を修飾しないかぎり、ループの内側から参照できません。

レコード中のフィールドには、暗黙のうちにフェッチされた行の列値が格納されます。フィールドの名前とデータ型は、対応する列の名前とデータ型と同じです。フィールドの値にアクセスするには、次のようにドット表記法を使用します。

record_name.field_name

FORループのカーソルによってフェッチされた選択項目の名前は、単純名にしてください。また、それらが式である場合は、別名を持つ必要があります。次の例では、選択項目sal+NVL(comm,0)の別名として wagesを指定しています。

CURSOR c1 IS SELECT empno, sal+comm wages, job ...

REVERSEデフォルトでは、反復は、範囲の下限から上限に上向きに進みます。キーワード REVERSEを使用すると、反復は上限から下限に下向きに進みます。

次に例を示します。

FOR i IN REVERSE 1..10 LOOP -- i starts at 10, ends at 1 -- statements here execute 10 timesEND LOOP;

ループ索引には upper_boundの値が割り当てられます。この値が lower_boundの値を下回っていない場合、ループの中の一連の文が実行され、索引が減分されます。索引の値がまだ lower_boundの値を下回っていない場合、一連の文がもう一度実行されます。この処理は、索引の値が lower_boundの値を下回るまで繰り返されます。下回った時点で、ループが終了します。

select_statement使用不可能な内部カーソルに関連付けられた問合せです。構文はselect_into_statementの構文と似ていますが、INTO句は使用できません。13-162ページの「SELECT INTO 文」を参照してください。PL/SQL は内部カーソルを自動的に宣言し、オープンし、データをフェッチしてクローズします。select_statementは独立した文ではないため、暗黙カーソル SQLは適用されません。

while_loop_statementWHILE-LOOP文は、ブール式を、キーワード LOOPと END LOOPで囲まれた一連の文に関連付けます。ループを反復する前に条件が評価されます。式が TRUEを戻す場合、一連の文が実行されてから、ループの先頭で制御が再開します。式が FALSEまたは NULLを戻す場合、ループは実行されず、制御は次の文に渡されます。

PL/SQL の言語要素 13-111

Page 520: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

LOOP 文

使用上の注意使用上の注意使用上の注意使用上の注意

EXIT WHEN文を使用すると、任意のループを途中で終了できます。WHEN句の中のブール式が TRUEを戻す場合、ループはただちに終了します。

カーソル FORループを終了すると、EXIT文または GOTO文を使用してループを途中で終了した場合でも、カーソルは自動的にクローズされます。ループの内側で例外が呼び出された場合も、カーソルは自動的にクローズされます。

例例例例

次のカーソル FORループでは、ボーナスを計算し、その結果をデータベース表に挿入しています。

DECLARE bonus REAL; CURSOR c1 IS SELECT empno, sal, comm FROM emp;BEGIN FOR c1rec IN c1 LOOP bonus := (c1rec.sal * 0.05) + (c1rec.comm * 0.25); INSERT INTO bonuses VALUES (c1rec.empno, bonus); END LOOP; COMMIT;END;

関連項目関連項目関連項目関連項目

カーソル、EXIT 文、FETCH 文、OPEN 文、%ROWTYPE 属性

13-112 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 521: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

MERGE 文

MERGE 文文文文

MERGE文は、一部の行の挿入と他の行の更新を 1 回の操作で行います。ターゲット表に対して更新と挿入のどちらを行うかは、結合条件に基づいて決定されます。つまり、ターゲット表のうち結合条件と一致する既存の行は更新され、それ以外の場合は別個の副問合せからの値を使用して 1 行が挿入されます。

MERGE文の詳細と例は、『Oracle Database SQL リファレンス』を参照してください。

使用上の注意使用上の注意使用上の注意使用上の注意

この文は、主として大量のデータが頻繁に挿入および更新されるデータ・ウェアハウスの場合に有効です。単一の行のみを挿入または更新する必要がある場合は、通常の PL/SQL で処理を実行する方が効率的です。行の更新を試みて、更新される行がない場合はかわりに挿入を行い、行の挿入を試みて、表がすでにその主キーを含んでいるために例外が呼び出された場合はかわりに更新を行います。

PL/SQL の言語要素 13-113

Page 522: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

NULL 文

NULL 文文文文

NULL文は、制御を次の文に渡す以外は何もしません。IF-THEN句、ループまたはプロシージャの本体で、NULL文はプレースホルダの役割を果たします。詳細は、4-18 ページの

「NULL 文の使用」を参照してください。

構文構文構文構文

使用上の注意使用上の注意使用上の注意使用上の注意

NULL文には、条件文の意味とアクションを明確にすることによって、コードをわかりやすくする効果があります。読み手に対して、代替アクションを誤って見逃したのではなく、アクションが不要であると判断したことを伝えることができます。

IF文、例外ハンドラなどの PL/SQL の特定の句には、1 つ以上の実行可能文が必要です。NULL文を使用すると、アクションを実行することなく、これらの構造体をコンパイルできます。

次の文が実行可能文ではなく、END、END IFなどであるため、GOTO文で特定の場所に分岐できない場合があります。この場合、分岐する場所に NULL文を置くことができます。

NULL文とブール値 NULLは無関係です。

例例例例

次の例では、NULL文によって、販売員のみがコミッションを受け取れることを明確にしています。

IF job_title = 'SALESPERSON' THEN compute_commission(emp_id);ELSE NULL;END IF;

次の例では、NULL文によって、名前のない例外ではアクションを実行しないことを示します。

EXCEPTION ... WHEN OTHERS THEN NULL;

NULL ;

null_statement

13-114 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 523: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

オブジェクト型オブジェクト型オブジェクト型オブジェクト型

オブジェクト型は、データの操作に必要なファンクションおよびプロシージャとともにデータ構造をカプセル化するユーザー定義の複合データ型です。データ構造を形成する変数は、属性属性属性属性と呼ばれます。オブジェクト型の動作を特徴付けるファンクションとプロシージャはメメメメソッドソッドソッドソッドと呼ばれます。コンストラクタコンストラクタコンストラクタコンストラクタと呼ばれる特殊な種類のメソッドは、オブジェクト型の新規インスタンスを作成し、その属性を記入します。

オブジェクト型は、SQL で作成し、Oracle データベースに格納して、多くのプログラムで共有できるようにする必要があります。CREATE TYPE文を使用してオブジェクト型を定義する場合は、実世界のオブジェクトに対応する抽象テンプレートを作成します。テンプレートでは、アプリケーション環境でオブジェクトに必要な属性と動作を指定します。

属性の集合によって形成されるデータ構造はパブリック(クライアント・プログラムから参照可能)です。ただし、優れたプログラムは、データ構造を直接操作しません。かわりに、提供される一連のメソッドを使用します。その結果、データは常に適切な状態に保たれます。

オブジェクト型の使用方法の詳細は、第 12 章「PL/SQL のオブジェクト型の使用」を参照してください。

構文構文構文構文

CREATEOR REPLACE

TYPEschema_name .

type_name

object_type_declaration | object_type_spec

AUTHIDCURRENT_USER

DEFINER IS

ASOBJECT ( member_list ) ;

attribute_name attribute_type

,

member_list

PL/SQL の言語要素 13-115

Page 524: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

attribute_datatypeLONG、LONG RAW、ROWID、UROWID、PL/SQL 固有の BINARY_INTEGER型とそのサブタイプ、BOOLEAN、PLS_INTEGER、RECORD、REF CURSOR、%TYPEおよび %ROWTYPEを除く任意の Oracle データ型と、PL/SQL パッケージ内に定義されている型です。

attribute_nameオブジェクト属性です。名前はそのオブジェクト型の中で一意である必要があります(他のオブジェクト型内では使用できます)。属性の宣言内では、代入演算子または DEFAULT句を使用しての属性の初期化はできません。また、属性に NOT NULL制約を課すことはできません。

,MAP

ORDERMEMBER function_spec

CREATEOR REPLACE

TYPE BODYschema_name .

type_name

object_type_body

MAP

ORDERMEMBER function_body ;

END ;

IS

AS

MEMBER

CONSTRUCTOR

STATIC

subprogram_body

call_spec ;

,

MEMBER

CONSTRUCTOR

STATIC

subprogram_spec

call_spec

, PRAGMA_RESTRICT_REFERENCES

13-116 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 525: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

AUTHID 句句句句

すべてのメンバー・メソッドがその定義者(デフォルト)と実行者のどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が定義者と実行者のどちらのスキーマで解決されるかを決定します。詳細は、8-20 ページの「実行者権限と定義者権限の使用

(AUTHID 句)」を参照してください。

call_specOracle データ・ディクショナリ内の外部 C ファンクションまたは Java メソッドを発行します。これは、対応する SQL に名前、パラメータ型および戻り型をマップすることによって、ルーチンを発行します。Java コール仕様を作成する方法は、『Oracle Database Java 開発者ガイド』を参照してください。C コール仕様を作成する方法は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

function_bodyCONSTRUCTOR、MEMBERまたは STATICファンクションを実装します。function_bodyの構文は、13-90 ページの「ファンクション」を参照してください。

MAPメソッドによるオブジェクトの順序付けが、オブジェクトを事前定義の順序を持つ CHARやREALなどのスカラー・データ型の値にマップすることで行われることを示します。PL/SQL は、この順序付けを使用して、x > yなどのブール式を評価し、DISTINCT、GROUP BYおよび ORDER BY句によって暗黙的に必要となる比較を実行します。マップ・メソッドは、すべてのオブジェクトを順序付けする際の、オブジェクトの相対的な位置を戻します。

1 つのオブジェクト型のマップ・メソッドは 1 つのみです。このメソッドは、DATE、NUMBER、VARCHAR2、または CHARACTERや INTEGER、REALなどの ANSI SQL 型のいずれかを戻り型として持つ、パラメータのないファンクションである必要があります。

MEMBER | CONSTRUCTOR | STATICオブジェクト型仕様部で、サブプログラムまたはコール仕様をメソッドとして宣言します。コンストラクタ・メソッドには、オブジェクト型と同じ名前が必要です。一方、メンバー・メソッドと静的メソッドには、オブジェクト型またはその属性とは異なる名前が必要です。

MEMBERメソッドはオブジェクトのインスタンスで起動され、その特定のインスタンスの属性の読取りや変更を行います。

object_instance.method();

CONSTRUCTORメソッドはオブジェクトの新規インスタンスを作成し、一部またはすべての属性を記入します。

object_instance := new object_type_name(attr1 => attr1_value, attr2 => attr2_value);

PL/SQL の言語要素 13-117

Page 526: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

各オブジェクトの属性に対して 1 つのパラメータを持つデフォルト・コンストラクタ・メソッドは、システムによって定義されます。したがって、独自のコンストラクタ・メソッドの定義が必要なのは、異なるパラメータのセットに基づいてオブジェクトを構成する場合のみです。

STATICメソッドはオブジェクト型で(特定のオブジェクト・インスタンスではなく)起動されます。したがって、このメソッドはオブジェクトの属性に関係のないグローバルな操作に制限する必要があります。

object_type.method()

オブジェクト型仕様部内のそれぞれのサブプログラム仕様部に対応するサブプログラム本体が、オブジェクト型本体内に存在している必要があります。仕様部と本体を一致させるために、コンパイラは、それらのヘッダーをトークンごとに比較します。このため、ヘッダーは一語一語が一致している必要があります。空白は異なっていてもかまいません。

CONSTRUCTORメソッドと MEMBERメソッドは、SELFという名前の組込みパラメータを受け入れます。このパラメータはオブジェクト型のインスタンスです。暗黙的宣言か明示的宣言かにかかわらず、SELF は常に MEMBERメソッドに渡される第 1 パラメータです。ただし、STATICメソッドは SELFの受入れや参照ができません。

メソッドの本体では、SELFはメソッドが起動されたオブジェクトを示します。たとえば、メソッド transformは SELFを IN OUTパラメータとして宣言します。

CREATE TYPE Complex AS OBJECT ( MEMBER FUNCTION transform (SELF IN OUT Complex) ...

SELFにそれ以外のデータ型は指定できません。コンストラクタ・ファンクションの場合、SELF のパラメータは、常に IN OUTモードです。MEMBERファンクションでは、SELFが宣言されていない場合、そのパラメータ・モードはデフォルトで INに設定されます。MEMBERプロシージャで SELFが宣言されていない場合、そのパラメータ・モードはデフォルトでIN OUTに設定されます。SELFには OUTパラメータ・モードを指定できません。

ORDER2 つのオブジェクトを比較するメソッドであることを示します。1 つのオブジェクト型のオーダー・メソッドは 1 つのみです。このメソッドは、戻り型が数値のファンクションである必要があります。

オーダー・メソッドはいずれも、組込みパラメータ SELFと、同じ型の別のオブジェクトの2 つのパラメータのみを取ります。c1および c2が Customerオブジェクトの場合、c1 > c2などの比較操作を実行すると、自動的にメソッド matchがコールされます。このメソッドの戻り値は、負数、0(ゼロ)、または正数であり、それぞれ SELFが他方のパラメータより小さい、等しい、大きいことを示しています。オーダー・メソッドに渡されるパラメータのいずれかが NULL の場合、メソッドは NULL を戻します。

13-118 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 527: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

pragma_restrict_refs純正規則に違反していないか確認できるプラグマです。メンバー関数は、副作用を制御するための規則に従っている場合にのみ、SQL 文からコールできます。ファンクション本体内のSQL 文が規則に違反すると、実行時(文が解析されるとき)にエラーが発生します。プラグマの構文は、13-150 ページの「RESTRICT_REFERENCES プラグマ」を参照してください

(この場合、プラグマの終了記号は省略してください)。

このプラグマは、メンバー関数がデータベース表またはパッケージ変数に対する読込みまたは書込みを行っていないことを示します。純正規則と RESTRICT_REFERENCESプラグマの詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

schema_nameオブジェクト型が含まれているスキーマを識別します。schema_nameを省略すると、オブジェクト型はユーザーのスキーマ内に存在するとみなされます。

subprogram_bodyMEMBERまたは STATICファンクションあるいはプロシージャを実装します。構文は、function_bodyや procedure_bodyの構文と似ていますが、終了記号は使用できません。13-90 ページの「ファンクション」または 13-138 ページの「プロシージャ」(あるいはその両方)を参照してください。

subprogram_specCONSTRUCTOR、MEMBERまたは STATICファンクションあるいはプロシージャへのインタフェースを宣言します。構文は、function_specや procedure_specの構文と似ていますが、終了記号は使用できません。13-90 ページの「ファンクション」または 13-138 ページの「プロシージャ」(あるいはその両方)を参照してください。

type_nameデータ型指定子 OBJECTを使用して定義したユーザー定義のオブジェクト型を識別します。

使用上の注意使用上の注意使用上の注意使用上の注意

オブジェクト型をスキーマに作成すると、任意の PL/SQL ブロック、サブプログラムまたはパッケージの中で、それを使用してオブジェクトを宣言できます。たとえば、そのオブジェクト型を使用すると、オブジェクト属性、表の列、PL/SQL 変数、バインド変数、レコード・フィールド、コレクション要素、プロシージャの仮パラメータまたはファンクション結果のデータ型を指定できます。

パッケージと同様に、オブジェクト型は仕様部と本体の 2 つの部分から構成されます。仕様部はアプリケーションへのインタフェースです。ここでは、データ構造(属性の集合)とデータ操作に必要な演算(メソッド)を宣言します。本体ではメソッドを完全に定義し、それによって仕様部を実装します。

PL/SQL の言語要素 13-119

Page 528: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

メソッドを使用するためにクライアント・プログラムが必要とするすべての情報は、仕様部にあります。仕様部は操作インタフェース、そして本体はブラック・ボックスと考えてください。仕様部を変更しなくても、本体をデバッグ、拡張または置換できます。

オブジェクト型はデータと操作をカプセル化します。属性とメソッドはオブジェクト型仕様部で宣言できますが、定数、例外、カーソル、型は宣言できません。少なくとも 1 つの属性が必要です( 大で 1000)。メソッドはオプションです。

オブジェクト型の仕様部では、メソッドより前にすべての属性を宣言する必要があります。サブプログラムのみが実装を必要とします。オブジェクト型の仕様部に属性およびコール仕様の宣言のみがある場合、またはそのいずれかの宣言のみがある場合、オブジェクト型本体は不要です。本体では属性を宣言できません。オブジェクト型の仕様部のすべての宣言は、パブリック(オブジェクト型の外側から参照可能)です。

属性は、オブジェクト型内の位置によってではなく、名前によってのみ参照できます。属性にアクセスしたり、その値を変更するには、ドット表記法を使用します。属性名を連鎖させて、ネストされたオブジェクト型の属性にアクセスできます。

オブジェクト型の中でメソッドは、修飾子なしで属性および他のメソッドを参照できます。SQL 文からパラメータのないメソッドをコールするには、空のパラメータ・リストが必要です。プロシージャ文では、コールを連鎖しないかぎり空のパラメータ・リストはなくてもかまいません。連鎖する場合は、 後のコール以外のすべてのコールで空のパラメータ・リストが必要です。

SQL 文からは、NULL インスタンス(SELFが NULL である状態)で MEMBERメソッドをコールすると、メソッドは起動されず NULL が戻されます。プロシージャ文からは、NULLインスタンスで MEMBERメソッドをコールすると、メソッドが起動される前に事前定義の例外 SELF_IS_NULLが呼び出されます。

マップ・メソッドかオーダー・メソッドを宣言できますが、その両方は宣言できません。どちらかのメソッドを宣言すれば、オブジェクトを SQL 文およびプロシージャ文によって比較できます。ただし、どちらのメソッドも宣言しなければ、オブジェクトは SQL 文でのみ比較し、しかも比較できるのは等しいか等しくないかについてのみです。同じ型の 2 つのオブジェクトが等しいとされるのは、それらの対応する属性の値が等しい場合のみです。

パッケージ化されたサブプログラムと同じく、同じ種類(ファンクションまたはプロシージャ)のメソッドはオーバーロードできます。つまり、仮パラメータの数、順序、またはデータ型の種類が違っていれば、同じ名前を複数の異なるメソッドで使用できます。

どのオブジェクト型にもデフォルト・コンストラクタ・メソッド(略してコンストラクタ)があります。このコンストラクタは、そのオブジェクト型と同じ名前のシステム定義のファンクションです。コンストラクタは、そのオブジェクト型のインスタンスを初期化したり、そのインスタンスを戻すために使用します。異なるパラメータのセットを受け入れる独自のコンストラクタ・メソッドを定義することもできます。PL/SQL は、暗黙的にコンストラクタをコールすることはないため、明示的にコールする必要があります。コンストラクタは、ファンクション・コールが許可されているところでコールできます。

13-120 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 529: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

例例例例

次の SQL*Plus スクリプトでは、スタックのためのオブジェクト型を定義しています。スタックに 後に追加された項目が、 初に削除される項目となります。スタックは、操作push および pop によって、後入れ先出し(LIFO)方式で更新されます。スタックの も簡単な実装は、整数の配列を使用します。整数は配列要素として格納され、配列の片方の端がスタックの先頭を表します。

CREATE TYPE IntArray AS VARRAY(25) OF INTEGER;

CREATE TYPE Stack AS OBJECT ( max_size INTEGER, top INTEGER, position IntArray, MEMBER PROCEDURE initialize, MEMBER FUNCTION full RETURN BOOLEAN, MEMBER FUNCTION empty RETURN BOOLEAN, MEMBER PROCEDURE push (n IN INTEGER), MEMBER PROCEDURE pop (n OUT INTEGER));

CREATE TYPE BODY Stack AS MEMBER PROCEDURE initialize IS -- fill stack with nulls BEGIN top := 0; -- call constructor for varray and set element 1 to NULL position := IntArray(NULL); max_size := position.LIMIT; -- use size constraint (25) position.EXTEND(max_size - 1, 1); -- copy element 1 END initialize;

MEMBER FUNCTION full RETURN BOOLEAN IS -- return TRUE if stack is full BEGIN RETURN (top = max_size); END full;

MEMBER FUNCTION empty RETURN BOOLEAN IS -- return TRUE if stack is empty BEGIN RETURN (top = 0); END empty;

MEMBER PROCEDURE push (n IN INTEGER) IS -- push integer onto stack BEGIN IF NOT full THEN

PL/SQL の言語要素 13-121

Page 530: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

top := top + 1; position(top) := n; ELSE -- stack is full RAISE_APPLICATION_ERROR(-20101, 'stack overflow'); END IF; END push;

MEMBER PROCEDURE pop (n OUT INTEGER) IS -- pop integer off stack and return its value BEGIN IF NOT empty THEN n := position(top); top := top - 1; ELSE -- stack is empty RAISE_APPLICATION_ERROR(-20102, 'stack underflow'); END IF; END pop;END;

メソッド pushおよび popでは、組込みプロシージャ raise_application_errorによってユーザー定義のエラー・メッセージを発行します。このようにして、エラーをクライアント・プログラムに報告し、未処理の例外をホスト環境に戻さないようにできます。次の例が示すように、オブジェクト型の中でメソッドは、修飾子なしで属性および他のメソッドを参照できます。

CREATE TYPE Stack AS OBJECT ( top INTEGER, MEMBER FUNCTION full RETURN BOOLEAN, MEMBER PROCEDURE push (n IN INTEGER), ...);

CREATE TYPE BODY Stack AS ... MEMBER PROCEDURE push (n IN INTEGER) IS BEGIN IF NOT full THEN top := top + 1; ... END push;END;

13-122 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 531: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

オブジェクト型

次の例では、オブジェクト型のネストを示します。

CREATE TYPE Address AS OBJECT ( street_address VARCHAR2(35), city VARCHAR2(15), state CHAR(2), zip_code INTEGER);

CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(15), last_name VARCHAR2(15), birthday DATE, home_address Address, -- nested object type phone_number VARCHAR2(15), ss_number INTEGER,);

関連項目関連項目関連項目関連項目

ファンクション、パッケージ、プロシージャ

PL/SQL の言語要素 13-123

Page 532: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN 文

OPEN 文文文文

OPEN文は、カーソルに関連付けられた問合せを実行します。また、問合せの処理に使用するデータベース・リソースを割り当て、結果セット(問合せの条件に一致する行)を識別します。カーソルは、結果セットの 初の行の前に置かれます。詳細は、6-11 ページの

「PL/SQL を使用したデータの問合せ」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name現行の有効範囲のうちそれより前に宣言されていて、現在オープンされていない明示カーソルです。

cursor_parameter_nameカーソルの仮パラメータとして宣言された変数を識別します。

(cursor_parameter_declarationの構文は、13-53 ページの「カーソル」を参照してください。)カーソルのパラメータは、問合せの中で定数が使用できる場所であれば、どこででも使用できます。

使用上の注意使用上の注意使用上の注意使用上の注意

一般に、PL/SQL による明示カーソルは、それを 初にオープンするときにのみ解析されます。また、SQL 文の解析(およびそれによる暗黙カーソルの作成)は、その文が初めて実行されるときにのみ行われます。解析された SQL 文は、すべてキャッシュに入れられます。SQL 文は、新しい SQL 文によってキャッシュからエージ・アウトされた場合にのみ再解析されます。したがって、カーソルを再オープンするには、まずクローズする必要がありますが、PL/SQL はカーソルに関連付けられた SELECT文を再解析する必要はありません。カーソルをクローズしてからただちに再オープンした場合、再解析は不要です。

結果セットの中の行は、OPEN文の実行時には取り出されません。行の取出しには FETCH文を使用します。FOR UPDATEカーソルでは、カーソルがオープンされるときに、行はロックされます。

OPEN cursor_name( cursor_parameter_name

,

);

open_statement

13-124 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 533: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN 文

仮パラメータが宣言されている場合は、カーソルに実パラメータを渡す必要があります。カーソルの仮パラメータは INパラメータにする必要があるため、実パラメータに値を戻すことはできません。実パラメータの値はカーソルをオープンする場合に使用されます。仮パラメータと実パラメータのデータ型には、互換性が必要です。問合せでは、有効範囲の中で宣言されている他の PL/SQL 変数を参照することもできます。

デフォルト値を受け入れるのでなければ、カーソル宣言の中の仮パラメータは、すべてOPEN文の中で対応する実パラメータを持つ必要があります。デフォルト値で宣言された仮パラメータの詳細は、対応する実パラメータがなくてもかまいません。このような仮パラメータは、OPEN文の実行時にデフォルト値を取ります。

位置表記法または名前表記法を使用して、OPEN文の実パラメータを、カーソル宣言の仮パラメータに関連付けることができます。

カーソルがオープンされている場合は、そのカーソルの名前をカーソル FORループで使用できません。

例例例例

次のようなカーソル宣言の場合、

CURSOR parts_cur IS SELECT part_num, part_price FROM parts;

次の文はカーソルをオープンします。

OPEN parts_cur;

次のようなカーソル宣言の場合、

CURSOR emp_cur(my_ename VARCHAR2, my_comm NUMBER DEFAULT 0) IS SELECT * FROM emp WHERE ...

次の文はいずれもカーソルをオープンします。

OPEN emp_cur('LEE');OPEN emp_cur('BLAKE', 300);OPEN emp_cur(employee_name, 150);

関連項目関連項目関連項目関連項目

CLOSE 文、カーソル、FETCH 文、LOOP 文

PL/SQL の言語要素 13-125

Page 534: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR 文

OPEN-FOR 文文文文

OPEN-FOR文は、カーソル変数に関連付けられている問合せを実行します。また、問合せの処理に使用するデータベース・リソースを割り当て、結果セット(問合せの条件を満たす行)を識別します。カーソル変数は、結果セットの中の 初の行の前に配置します。詳細は、6-25 ページの「カーソル変数(REF CURSOR)の使用」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_variable_name現行の有効範囲のうちそれより前に宣言されているカーソル変数(またはパラメータ)です。

host_cursor_variable_namePL/SQL ホスト環境で事前に宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

select_statementcursor_variableに関連付けられた問合せです。一連の値を戻します。問合せでは、バインド変数、PL/SQL 変数、パラメータ、ファンクションを参照できます。select_statementの構文は、13-162 ページの「SELECT INTO 文」で定義されているselect_into_statementの構文に似ていますが、select_statementカーソルでは、INTO句は使用できません。

OPENcursor_variable_name

: host_cursor_variable_nameFOR select_statement ;

open_for_statement

13-126 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 535: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR 文

使用上の注意使用上の注意使用上の注意使用上の注意

OCI や Pro*C プログラムなどの PL/SQL ホスト環境で、カーソル変数を宣言できます。ホスト・カーソル変数をオープンするには、バインド変数として無名 PL/SQL ブロックに渡します。OPEN-FOR文をグループにまとめることで、ネットワークの通信量を削減できます。たとえば、次の PL/SQL ブロックは、1 回の往復で 5 つのカーソル変数をオープンしています。

/* anonymous PL/SQL block in host environment */ BEGIN OPEN :emp_cv FOR SELECT * FROM emp; OPEN :dept_cv FOR SELECT * FROM dept; OPEN :grade_cv FOR SELECT * FROM salgrade; OPEN :pay_cv FOR SELECT * FROM payroll; OPEN :ins_cv FOR SELECT * FROM insurance; END;

その他の OPEN-FOR文は、異なる複数の問合せ用に同じカーソル変数をオープンできます。カーソル変数を再オープンする場合、その前にクローズする必要はありません。別の問合せ用にカーソル変数を再オープンすると、前の問合せは失われます。

カーソルとは異なり、カーソル変数はパラメータを取りません。かわりに、カーソル変数にはパラメータのみでなく問合せ全体を渡すことができます。

カーソル変数は、PL/SQL ストアド・プロシージャまたはファンクションによってオープンして、コール元のサブプログラムに戻すことができますが、コール元とコール先のサブプログラムは同じインスタンス上に存在する必要があります。データベース・リンクを介してコールされたプロシージャおよびファンクションに、カーソル変数を渡したり、戻すことはできません。

カーソル変数を、そのカーソル変数をオープンするサブプログラムの仮パラメータとして宣言する場合は、IN OUTモードを指定する必要があります。この指定によって、サブプログラムはコール元にオープン・カーソルを渡すことができます。

PL/SQL の言語要素 13-127

Page 536: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR 文

例例例例

データ検索を集中的に実行するために、ストアド・プロシージャの中で型互換性のある問合せをグループにまとめることができます。次のパッケージ・プロシージャは、選択された問合せ用にカーソル変数 emp_cvをオープンします。

CREATE PACKAGE emp_data AS TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice IN INT);END emp_data;

CREATE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp, choice IN INT) IS BEGIN IF choice = 1 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE comm IS NOT NULL; ELSIF choice = 2 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE sal > 2500; ELSIF choice = 3 THEN OPEN emp_cv FOR SELECT * FROM emp WHERE deptno = 20; END IF; END;END emp_data;

さらに柔軟性を高めるために、カーソル変数と選択子を、異なる戻り値の型を指定した問合せを実行するストアド・プロシージャに渡すことができます。次に例を示します。

CREATE PACKAGE admin_data AS TYPE GenCurTyp IS REF CURSOR; PROCEDURE open_cv (generic_cv IN OUT GenCurTyp, choice INT);END admin_data;

CREATE PACKAGE BODY admin_data AS PROCEDURE open_cv (generic_cv IN OUT GenCurTyp, choice INT) IS BEGIN IF choice = 1 THEN OPEN generic_cv FOR SELECT * FROM emp; ELSIF choice = 2 THEN OPEN generic_cv FOR SELECT * FROM dept; ELSIF choice = 3 THEN OPEN generic_cv FOR SELECT * FROM salgrade; END IF; END;END admin_data;

関連項目関連項目関連項目関連項目

CLOSE 文、カーソル変数、FETCH 文、LOOP 文

13-128 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 537: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR-USING 文

OPEN-FOR-USING 文文文文

OPEN-FOR-USING文は、カーソル変数を問合せに関連付けて、問合せを実行し、結果セットを識別してカーソルを結果セットの 初の行の前に配置してから、%ROWCOUNTによって保持される処理行カウントを 0(ゼロ)に設定します。詳細は、7-5 ページの「動的 SQL を使用した動的問合せの構築」を参照してください。

OPEN-FOR-USING文は、バインド変数を使用して SQL の処理効率を向上させることができるため、WHERE句が事前に判明している問合せを構築する場合は、この文を使用します。WHERE句の数が不明な動的問合せを処理するために柔軟性が必要な場合は、OPEN-FOR文を使用します。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_variable_name現行の有効範囲内でそれより前に宣言されている、弱い型指定の(戻り型を持たない)カーソル変数です。

bind_argument動的 SELECT文に渡される値を持つ式です。

dynamic_string複数行の SELECT文を表す文字列リテラル、変数または式です。

OPENcursor_variable_name

: host_cursor_variable_nameFOR dynamic_string

open_for_using_statement

USING bind_argument

,

;

PL/SQL の言語要素 13-129

Page 538: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR-USING 文

host_cursor_variable_namePL/SQL ホスト環境で宣言され、バインド変数として PL/SQL に渡されるカーソル変数を識別します。ホスト・カーソル変数のデータ型は、PL/SQL カーソル変数の戻り型と互換性があります。ホスト変数には、接頭辞としてコロンを付けてください。

USING ...バインド引数のリストを指定するオプションの句です。実行時に、USING句のバインド引数は動的 SELECT文内の対応するプレースホルダを置き換えます。

使用上の注意使用上の注意使用上の注意使用上の注意

動的な複数行の問合せを処理するには、OPEN-FOR-USING文、FETCH文および CLOSE文の 3 つの文を使用します。まず、OPEN-FOR文でカーソル変数を複数行問合せ用にオープンします。次に、FETCH文で結果セットから行を取り出します。すべての行が処理された後に、CLOSE文でカーソル変数をクローズします。

動的文字列には、任意の複数行 SELECT文(終了記号を持たない)を含むことができます。また、バインド引数のプレースホルダも含めることができます。ただし、バインド引数を使用してスキーマ・オブジェクトの名前を動的 SQL 文に渡すことはできません。

動的文字列内のすべてのプレースホルダは、USING句内のバインド引数に関連付ける必要があります。USING句内では数値リテラル、文字リテラル、および文字列リテラルは使用できますが、ブール・リテラル(TRUE、FALSE、NULL)は使用できません。動的文字列にNULL を渡すには、回避策を使用する必要があります。7-13 ページの「動的 SQL へのNULL の引渡し」を参照してください。

カーソル変数がオープンしている場合にのみ、問合せの中のバインド引数が評価されます。異なるバインド値を使用してカーソルからフェッチするには、新しい値に設定されたバインド引数でカーソル変数を再オープンする必要があります。

動的 SQL はすべての SQL データ型をサポートしています。たとえば、バインド引数をコレクション、LOB、オブジェクト型のインスタンスおよび ref とすることができます。通常、動的 SQL は PL/SQL 固有の型をサポートしていません。たとえばバインド引数をブールまたは索引付き表にできません。

13-130 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 539: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

OPEN-FOR-USING 文

例例例例

次の例では、カーソル変数を宣言し、そのカーソル変数を動的 SELECT文に関連付けます。

DECLARE TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type emp_cv EmpCurTyp; -- declare cursor variable my_ename VARCHAR2(15); my_sal NUMBER := 1000;BEGIN OPEN emp_cv FOR -- open cursor variable 'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal; ...END;

関連項目関連項目関連項目関連項目

EXECUTE IMMEDIATE 文、OPEN-FOR 文

PL/SQL の言語要素 13-131

Page 540: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

パッケージパッケージパッケージパッケージ

パッケージとは、論理的に関連する PL/SQL の型、項目およびサブプログラムをグループにまとめたスキーマ・オブジェクトのことです。再利用の可能性がある Application Program Interface(API)を構成する一連の関連サブプログラムを作成する場合にパッケージを使用します。パッケージには、仕様部と本体の 2 つの部分があります。詳細は、第 9 章

「PL/SQL パッケージの使用」を参照してください。

構文構文構文構文

CREATEOR REPLACE

PACKAGEschema_name .

package_name

package_declaration | package_spec

collection_type_definition

record_type_definition

subtype_definition

collection_declaration

constant_declaration

exception_declaration

object_declaration

record_declaration

variable_declaration

cursor_spec

function_spec

procedure_spec

call spec

pragma_restrict_refs

ENDpackage_name

;

AUTHIDCURRENT_USER

DEFINER IS

AS

PRAGMA SERIALLY_REUSABLE ;

13-132 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 541: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

CREATEOR REPLACE

PACKAGE BODYschema_name .

package_name

package_body

collection_type_definition

record_type_definition

subtype_definition

collection_declaration

constant_declaration

exception_declaration

object_declaration

record_declaration

variable_declaration

cursor_body

function_body

procedure_body

call spec

BEGIN statementEND

package_name;

IS

AS

PRAGMA SERIALLY_REUSABLE ;

PL/SQL の言語要素 13-133

Page 542: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

AUTHIDすべてのパッケージ・サブプログラムがその定義者(デフォルト)と実行者のどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が定義者と実行者のどちらのスキーマで解決されるかを決定します。詳細は、8-20 ページの「実行者権限と定義者権限の使用(AUTHID 句)」を参照してください。

call_specOracle データ・ディクショナリ内の外部 C ファンクションまたは Java メソッドを発行します。これは、対応する SQL に名前、パラメータ型および戻り型をマップすることによって、ルーチンを発行します。詳細は、『Oracle Database Java 開発者ガイド』および『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

collection_declarationコレクション(ネストした表、索引付き表または VARRAY)を宣言します。collection_declarationの構文は、13-29 ページの「コレクション」を参照してください。

collection_type_definitionデータ型指定子 TABLEまたは VARRAYを使用してコレクション型を定義します。

constant_declaration定数を宣言します。constant_declarationの構文は、13-39 ページの「定数と変数」を参照してください。

cursor_body明示カーソルの基盤となる実装を定義します。cursor_bodyの構文は、13-53 ページの

「カーソル」を参照してください。

cursor_spec明示カーソルへのインタフェースを宣言します。cursor_specの構文は、13-53 ページの

「カーソル」を参照してください。

exception_declaration例外を宣言します。exception_declarationの構文は、13-62 ページの「例外」を参照してください。

13-134 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 543: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

function_bodyファンクションを実装します。function_bodyの構文は、13-90 ページの「ファンクション」を参照してください。

function_specファンクションへのインタフェースを宣言します。function_specの構文は、13-90 ページの「ファンクション」を参照してください。

object_declarationオブジェクト(オブジェクト型のインスタンス)を宣言します。object_declarationの構文は、13-115 ページの「オブジェクト型」を参照してください。

package_nameデータベースに格納されたパッケージを識別します。ネーミング規則は、2-4 ページの「識別子」を参照してください。

pragma_restrict_refs純正規則に違反していないか確認できるプラグマです。ファンクションは、副作用を制御する規則に従っている場合にのみ、SQL 文からコールできます。ファンクション本体内のSQL 文が規則に違反すると、実行時(文が解析されるとき)にエラーが発生します。プラグマの構文は、13-150 ページの「RESTRICT_REFERENCES プラグマ」を参照してください。

プラグマは、ファンクションがデータベース表またはパッケージ変数(あるいはその両方)に対する読込みや書込み、またはそのいずれも行っていないことを示します。純正規則とRESTRICT_REFERENCESプラグマの詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

PRAGMA SERIALLY_REUSABLEサーバーへの 1 コール(サーバーへの OCI コール、サーバー間のリモート・プロシージャ・コールなど)の間のみパッケージを逐次再使用可能な状態にする必要がある場合は、パッケージに逐次再使用可能とマークします。詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

procedure_bodyプロシージャを実装します。procedure_bodyの構文は、13-138 ページの「プロシージャ」を参照してください。

procedure_specプロシージャへのインタフェースを宣言します。procedure_specの構文は、13-138 ページの「プロシージャ」を参照してください。

PL/SQL の言語要素 13-135

Page 544: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

record_declarationユーザー定義のレコードを宣言します。record_declarationの構文は、13-145 ページの

「レコード」を参照してください。

record_type_definitionデータ型指定子 RECORDまたは属性 %ROWTYPEを使用してレコード型を定義します。

schema_nameパッケージが含まれているスキーマを識別します。schema_nameを省略すると、パッケージはユーザーのスキーマ内に存在するとみなされます。

variable_declaration変数を宣言します。variable_declarationの構文は、13-39 ページの「定数と変数」を参照してください。

使用上の注意使用上の注意使用上の注意使用上の注意

PL/SQL をサポートする Oracle のツール製品を使用すると、パッケージを作成し、それをOracle データベース内に格納できます。CREATE PACKAGEおよび CREATE PACKAGE BODY文は、Oracle プリコンパイラか OCI ホスト・プログラムから、または SQL*Plus から対話形式で発行できます。

パッケージは、PL/SQL ブロックまたはサブプログラムの中では定義できません。

通常、パッケージには仕様部と本体があります。仕様部はアプリケーションへのインタフェースです。ここでは、使用できる型、変数、定数、例外、カーソル、サブプログラムなどを宣言します。本体ではカーソルとサブプログラムを完全に定義し、仕様を実装します。

下位の実装を持つのは、サブプログラムとカーソルのみです。仕様部で宣言されているのが型、定数、変数、例外およびコール仕様のみであれば、パッケージ本体は不要です。ただしその場合でも、次のようにパッケージ本体を使用して、仕様部で宣言した項目を初期化できます。

CREATE PACKAGE emp_actions AS ... number_hired INTEGER;END emp_actions;

CREATE PACKAGE BODY emp_actions ASBEGIN number_hired := 0;END emp_actions;

13-136 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 545: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パッケージ

仕様部は本体がなくてもコーディングし、コンパイルできます。仕様部のコンパイルが終了すると、そのパッケージを参照するストアド・サブプログラムもコンパイルできます。アプリケーション作成の 終段階になるまで、パッケージ本体を完全に定義する必要はありません。パッケージ本体は、パッケージ仕様部を変更せずに、デバッグ、拡張または置換できます。そのため、パッケージをコールするサブプログラムを再コンパイルする必要はありません。

パッケージ仕様部で宣言したカーソルとサブプログラムは、パッケージ本体で定義する必要があります。パッケージ仕様部で宣言したその他のプログラム項目は、パッケージ本体で再宣言できません。

サブプログラムの仕様部と本体を一致させるために、PL/SQL は、それらのヘッダーをトークンごとに比較します。このため、空白を除いて、ヘッダーは一語一語が一致している必要があります。一致していない場合は、PL/SQL によって例外が呼び出されます。

パッケージで宣言された変数は、セッションを通じてその値が保持されます。そのため、1つのプロシージャでパッケージ変数の値を設定して、その値を別のプロシージャで取り出すことができます。

関連項目関連項目関連項目関連項目

コレクション、カーソル、例外、ファンクション、プロシージャ、レコード

PL/SQL の言語要素 13-137

Page 546: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ

プロシージャプロシージャプロシージャプロシージャ

プロシージャとは、パラメータを指定してコールできるサブプログラムのことです。一般に、プロシージャはアクションを実行するために使用します。プロシージャには、仕様部と本体の 2 つの部分があります。仕様部は、キーワード PROCEDUREで始め、プロシージャ名またはパラメータ・リストで終わります。パラメータ宣言はオプションです。パラメータを取らないプロシージャではカッコを書きません。プロシージャの本体は、キーワード IS

(または AS)で始め、キーワード ENDで終わります。END の後には、オプションとしてプロシージャ名を続けることができます。

プロシージャ本体には、宣言部(オプション)、実行部、例外処理部(オプション)の 3 つの部分があります。宣言部には、型、カーソル、定数、変数、例外およびサブプログラムが含まれます。これらの項目はローカルで、プロシージャを終了すると消去されます。実行部には、値の代入、実行の制御および Oracle データの操作を実行する文があります。例外処理部には、実行の途中で呼び出された例外を処理する例外ハンドラがあります。詳細は、8-3ページの「PL/SQL プロシージャ」を参照してください。

構文構文構文構文

PROCEDURE procedure_name( parameter_declaration

,

);

procedure_spec

procedure_declaration | procedure body

( parameter_declaration

,

)AUTHID

CURRENT_USER

DEFINER IS

AS

CREATEOR REPLACE

PROCEDURE procedure_name

13-138 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 547: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

AUTHIDストアド・プロシージャをその所有者(デフォルト)と現行ユーザーのどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が所有者と現行ユーザーのどちらのスキーマで解決されるかを決定します。CURRENT_USERを指定すると、デフォルトの動作を変更できます。詳細は、8-20 ページの「実行者権限と定義者権限の使用(AUTHID句)」を参照してください。

CREATEOracle データベースに格納して、他のアプリケーションからコールできるストアド・プロシージャを作成するオプションの CREATE句です。CREATE文は、SQL*Plus またはシステム固有の動的 SQL を使用したプログラムから対話形式で実行できます。

datatype型指定子です。datatypeの構文は、13-39 ページの「定数と変数」を参照してください。

EXCEPTION exception_handlerEND

procedure_name;

parameter_name

IN

OUT

IN OUT

NOCOPY

datatype

parameter_declaration

:=

DEFAULTexpression

type_definition

item_declaration

function_declaration

procedure_declarationBEGIN statement

PRAGMA AUTONOMOUS_TRANSACTION ;

PL/SQL の言語要素 13-139

Page 548: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ

exception_handler例外ハンドラです。例外が呼び出されると、その例外に関連付けられた一連の文を実行します。exception_handlerの構文は、13-62 ページの「例外」を参照してください。

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。宣言が PL/SQL コンパイラによって処理されるときに、expressionの値がパラメータに代入されます。その値とパラメータのデータ型には互換性が必要です。

function_declarationファンクションを宣言します。function_declarationの構文は、13-90 ページの「ファンクション」を参照してください。

IN、、、、OUT、、、、IN OUT仮パラメータの動作を定義するパラメータ・モードです。INパラメータは、コールされるサブプログラムに値を渡します。OUTパラメータは、サブプログラムのコール元に値を戻します。IN OUTパラメータは、コール先のサブプログラムに初期値を渡して、更新された値をコール元に戻します。

item_declarationプログラム・オブジェクトを宣言します。item_declarationの構文は、13-11 ページの

「ブロック」を参照してください。

NOCOPYコンパイラ・ヒント(ディレクティブではなく)です。これによって、PL/SQL コンパイラは OUTおよび IN OUTパラメータを、デフォルトの値方式ではなく、参照方式で渡すことができます。詳細は、8-10 ページの「サブプログラムのパラメータのモードの指定」を参照してください。

parameter_name仮パラメータを識別します。仮パラメータとは、プロシージャの仕様部で宣言され、プロシージャ本体の中で参照される変数のことです。

AUTONOMOUS_TRANSACTION プラグマプラグマプラグマプラグマ

ファンクションを自律型としてマークします。自律型トランザクションは、メイン・トランザクションによって開始される独立したトランザクションです。自律型トランザクションを使用すると、メイン・トランザクションを停止し、SQL 操作を実行してその操作をコミットまたはロールバックしてから、メイン・トランザクションを再開できます。詳細は、6-45ページの「自律型トランザクションによる独立した作業単位の実行」を参照してください。

13-140 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 549: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ

procedure_nameユーザー定義のプロシージャです。

type_definitionユーザー定義のデータ型を指定します。type_definitionの構文は、13-11 ページの「ブロック」を参照してください。

:= | DEFAULTプロシージャがコールされたときに INパラメータに値が指定されていない場合、INパラメータをデフォルト値に初期化します。

使用上の注意使用上の注意使用上の注意使用上の注意

プロシージャは PL/SQL 文としてコールされます。たとえば、次のようにプロシージャraise_salaryをコールできます。

raise_salary(emp_num, amount);

プロシージャの中では、INパラメータは定数のように取り扱われるため、値は代入できません。OUTパラメータはローカル変数のように取り扱われるため、値を変更して参照できます。IN OUTパラメータは初期化された変数のように取り扱われるため、値を代入したり、その値を他の変数に代入できます。パラメータ・モードの概要は、8-11 ページの表 8-1 を参照してください。

OUTパラメータおよび IN OUTパラメータとは異なり、INパラメータはデフォルト値に初期化できます。詳細は、8-12 ページの「サブプログラムのパラメータのデフォルト値の使用」を参照してください。

プロシージャを終了する前に、すべての OUT仮パラメータに明示的に値を代入してください。OUT実パラメータには、サブプログラムがコールされる前にも値を入れることができます。ただし、サブプログラムをコールした時点で、値は失われます(コンパイラ・ヒントNOCOPYを指定しない場合、またはサブプログラムを未処理例外で終了しない場合)。

プロシージャの仕様部と本体を合わせて 1 つの単位として作成できます。また、プロシージャの仕様部と本体を別々にすることもできます。このように、プロシージャをパッケージに入れると、実装上の細部を隠ぺいできます。パッケージ仕様部でプロシージャ仕様部を宣言せずに、パッケージ本体でプロシージャを定義できます。ただし、このようなプロシージャはパッケージの内側からのみコールできます。

プロシージャの実行部には、少なくとも 1 つの文が存在している必要があります。NULL文はこの条件を満たします。

PL/SQL の言語要素 13-141

Page 550: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ

例例例例

次のプロシージャでは、銀行口座から出金します。

PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS old_balance REAL; new_balance REAL; overdrawn EXCEPTION;BEGIN SELECT bal INTO old_balance FROM accts WHERE acctno = acct_id; new_balance := old_balance - amount; IF new_balance < 0 THEN RAISE overdrawn; ELSE UPDATE accts SET bal = new_balance WHERE acctno = acct_id; END IF;EXCEPTION WHEN overdrawn THEN ...END debit_account;

次の例では、名前表記法を使用してプロシージャをコールします。

debit_account(amount => 500, acct_id => 10261);

関連項目関連項目関連項目関連項目

コレクション・メソッド、ファンクション、パッケージ

13-142 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 551: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RAISE 文

RAISE 文文文文

RAISE文は、PL/SQL ブロックまたはサブプログラムの通常の実行を停止させ、例外ハンドラに制御を移します。

ZERO_DIVIDE、NO_DATA_FOUNDなどの事前定義済の例外、またはユーザーが名前を付けたユーザー定義の例外を RAISE文で呼び出すことができます。詳細は、10-8 ページの「独自の PL/SQL 例外の定義」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

exception_name事前定義済の例外またはユーザー定義の例外を識別します。事前定義済の例外のリストは、10-5 ページの「事前定義の PL/SQL 例外のまとめ」を参照してください。

使用上の注意使用上の注意使用上の注意使用上の注意

PL/SQL ブロックとサブプログラムから RAISE文で例外を呼び出すのは、エラーのために処理を続行できなくなった場合のみにしてください。指定した例外に対する RAISE文は、その例外の有効範囲内であれば任意の場所にコーディングできます。

例外が呼び出されたときに、PL/SQL がその例外のハンドラをカレント・ブロックで発見できない場合は、ハンドラが見つかるまで、または検索するブロックがなくなるまで、例外が1 つずつ外側のブロックに伝播していきます。ハンドラが見つからなかった場合、PL/SQLはホスト環境に「未処理例外」エラーを戻します。

例外ハンドラの中の RAISE文で例外名を省略すると、現行の例外を再度呼び出すことができます。これによって、初期の対処措置(問題のログを記録するなど)を行ってから、より広範囲な対処を行う別のハンドラに制御を渡すことができます。例外が再度呼び出された場合、 初に検索されるブロックは、カレント・ブロックではなく外側のブロックです。

RAISEexception_name

;

raise_statement

PL/SQL の言語要素 13-143

Page 552: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RAISE 文

例例例例

次の例では、在庫部品が在庫切れになった場合、または 0(ゼロ)で割ろうとした場合に例外を呼び出します。

DECLARE out_of_stock EXCEPTION; quantity_on_hand NUMBER := 0; denominator NUMBER := 0;BEGIN IF quantity_on_hand = 0 THEN RAISE out_of_stock; END IF;

IF denominator = 0 THEN raise ZERO_DIVIDE; END IF;

EXCEPTION WHEN out_of_stock THEN dbms_output.put_line('No more parts in stock.'); WHEN ZERO_DIVIDE THEN dbms_output.put_line('Attempt to divide by zero.'); WHEN OTHERS THEN dbms_output.put_line('Some other kind of problem...');END;/

関連項目関連項目関連項目関連項目

例外

13-144 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 553: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード

レコードレコードレコードレコード

レコードは、様々な型のデータ値を格納できるコンポジット変数で、C、C++ または Java のstruct型に似ています。詳細は、5-41 ページの「PL/SQL レコード」を参照してください。

PL/SQL のレコードは、表の行から取り出したデータや特定の列を保持する場合に便利です。新しいレコード型を作成するかわりに、変数を table%ROWTYPE またはcursor%ROWTYPE として宣言して、メンテナンスを容易にできます。

構文構文構文構文

TYPE type_name IS RECORD ( field_declaration

,

) ;

record_type_definition

field_name datatype

NOT NULL :=

DEFAULTexpressionfield_declaration

record_name type_name ;

record_declaration

PL/SQL の言語要素 13-145

Page 554: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

datatypeデータ型指定子です。datatypeの構文は、13-39 ページの「定数と変数」を参照してください。

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。expressionの構文は、13-71 ページの「式」を参照してください。宣言が PL/SQL コンパイラによって処理されるとき、expressionの値がフィールドに代入されます。その値とフィールドのデータ型には互換性が必要です。

field_nameユーザー定義のレコード内のフィールドを識別します。

NOT NULL実行時に、NOT NULLとして定義されたフィールドに NULL を代入しようとすると、事前定義の例外 VALUE_ERRORが呼び出されます。NOT NULL制約の後には初期化句が続く必要があります。

record_nameユーザー定義のレコードを識別します。

type_nameデータ型指定子 RECORDを使用して定義されたユーザー定義のレコード型を識別します。

:= | DEFAULTフィールドをデフォルト値に初期化します。

13-146 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 555: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード

使用上の注意使用上の注意使用上の注意使用上の注意

RECORD型定義とユーザー定義レコードの宣言は、任意のブロック、サブプログラムまたはパッケージの宣言部でできます。

次に示すように、レコードを宣言の中で初期化できます。

DECLARE TYPE TimeTyp IS RECORD ( seconds SMALLINT := 0, minutes SMALLINT := 0, hours SMALLINT := 0 );

%TYPE属性を使用して、フィールドのデータ型を指定できます。また、フィールド宣言にNOT NULL制約を加えて、フィールドに NULL を代入できないようにすることもできます。NOT NULLと宣言されたフィールドは、初期化されている必要があります。

DECLARE TYPE DeptRecTyp IS RECORD ( deptno NUMBER(2) NOT NULL := 99, dname departments.department_name%TYPE, loc departments.location_id%TYPE, region regions%ROWTYPE ); dept_rec DeptRecTyp;BEGIN dept_rec.dname := 'PURCHASING';END;/レコード中の個々のフィールドを参照する場合は、ドット表記法を使用します。たとえば、レコード dept_recのフィールド dnameに値を代入する場合は、次のようにします。

dept_rec.dname := 'PURCHASING';

レコード中の個々のフィールドに別々に値を代入するかわりに、すべてのフィールドに値を一度に代入できます。

� 2 つのユーザー定義レコードのデータ型が同じであれば、一方のレコードをもう一方のレコードに代入できます。(正確に一致するフィールドが含まれているのみでは不十分です。)フィールドの数と順序が同じで、対応するフィールドのデータ型に互換性があれば、%ROWTYPEレコードをユーザー定義のレコードに代入できます。

� SELECT文または FETCH文を使用して列の値をフェッチし、レコードに代入できます。選択リストの列が、レコード中のフィールドと同じ順序で並ぶようにしてください。

ネストされたレコードを宣言し、参照できます。つまり、レコードを他のレコードの構成要素にできます。

DECLARE TYPE TimeTyp IS RECORD ( minutes SMALLINT, hours SMALLINT ); TYPE MeetingTyp IS RECORD (

PL/SQL の言語要素 13-147

Page 556: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード

day DATE, time_of TimeTyp, -- nested record dept departments%ROWTYPE, -- nested record representing a table row place VARCHAR2(20), purpose VARCHAR2(50) ); meeting MeetingTyp; seminar MeetingTyp;BEGIN seminar.time_of := meeting.time_of;END;/

2 つのネストされたレコードのデータ型が同じであれば、一方のレコードをもう一方のレコードに代入できます。

seminar.time_of := meeting.time_of;

このような代入は、親レコードが異なるデータ型を持っている場合でもできます。

ユーザー定義のレコードは、通常の有効範囲規則とインスタンス化の規則に従います。パッケージの中では、そのパッケージが初めて参照された時点でインスタンスが生成され、データベース・セッションが終わった時点で消滅します。ブロックまたはサブプログラムでは、ブロックまたはサブプログラムに入るときにインスタンス化され、ブロックまたはサブプログラムを終了すると消去されます。

スカラー変数と同様に、ユーザー定義のレコードもプロシージャやファンクションの仮パラメータとして宣言できます。スカラー・パラメータに適用されるのと同じ制限が、ユーザー定義のレコードにも適用されます。

ファンクション仕様部の RETURN句の中に RECORD型を指定できます。こうすると、ファンクションは同じ型のユーザー定義のレコードを戻します。ユーザー定義のレコードを戻すファンクションをコールする場合、次の構文を使用してレコード内のフィールドを参照します。

function_name(parameter_list).field_name

ネストしたフィールドを参照するには、次の構文を使用します。

function_name(parameter_list).field_name.nested_field_name

ファンクションがパラメータを取らない場合は、空のパラメータ・リストをコーディングします。次に構文を示します。

function_name().field_name

13-148 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 557: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

レコード

例例例例

次の例では、DeptRecTypという名前の RECORD型を定義し、dept_recという名前のレコードを宣言した後、行の値を選択してレコードに代入しています。

DECLARE TYPE DeptRecTyp IS RECORD ( deptno departments.department_id%TYPE, dname departments.department_name%TYPE, loc departments.location_id%TYPE ); dept_rec DeptRecTyp;BEGIN SELECT department_id, department_name, location_id INTO dept_rec FROM departments WHERE department_id = 20;END;/

関連項目関連項目関連項目関連項目

コレクション、ファンクション、パッケージ、プロシージャ

PL/SQL の言語要素 13-149

Page 558: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RESTRICT_REFERENCES プラグマ

RESTRICT_REFERENCES プラグマプラグマプラグマプラグマ

ストアド・ファンクションは、副作用を制御する特定の純正規則に従っている場合にのみ、SQL 文からコールできます。(8-29 ページの「PL/SQL サブプログラムの副作用の制御」を参照。)副作用が少なければ、特に PARALLEL_ENABLEヒントまたは DETERMINISTICヒントを使用している場合に、問合せ内でファンクションをより効率化できます。ファンクション自体に適用される規則が、そのファンクションがコールするファンクションまたはプロシージャにも適用されます。

ファンクション本体内の SQL 文が規則に違反すると、実行時(文が解析されるとき)にエラーが発生します。コンパイル時にこの規則に違反していないかどうかを確認するには、コンパイラ・ディレクティブである RESTRICT_REFERENCESプラグマを使用します。このプラグマは、ファンクションがデータベース表またはパッケージ変数(あるいはその両方)に対する読込みや書込み、またはそのいずれも行っていないことを示します。このような読込みや書込み操作を行っているファンクションは、コールによって結果が異なったり、エラーが発生する場合があるため、 適化は困難です。

詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

構文構文構文構文

PRAGMA RESTRICT_REFERENCES (function_name

DEFAULT,

RNDS

WNDS

RNPS

WNPS

TRUST

,

) ;

pragma_restrict_refs

13-150 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 559: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RESTRICT_REFERENCES プラグマ

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

DEFAULTプラグマがパッケージ仕様部またはオブジェクト型の仕様部の中のすべてのサブプログラムに適用されるように指定します。その場合でも、サブプログラムごとにプラグマを宣言できます。これらのプラグマは、デフォルトのプラグマをオーバーライドします。

function_nameユーザー定義のファンクションまたはプロシージャを識別します。

PRAGMA文がコンパイラ・ディレクティブであることを表します。プラグマは、実行時ではなくコンパイル時に処理されます。プログラムの機能に影響を与えず、コンパイラに情報を提供します。

RNDSサブプログラムがデータベースに読込み禁止状態である(データベース表を問合せできない)ことを示します。

RNPSサブプログラムがパッケージに読込み禁止状態である(パッケージ変数の値を参照できない)ことを示します。

TRUSTサブプログラムが 1 つ以上の規則に違反しないと信頼されていることを示します。C またはJava で記述されたファンクションを PL/SQL でコールする場合は、実行時にこれらのファンクションを検証できないため、この値が必要です。

WNDSサブプログラムがデータベースへの書込み禁止状態である(データベース表を変更できない)ことを示します。

WNPSサブプログラムがパッケージへの書込み禁止状態である(パッケージ変数の値を変更できない)ことを示します。

PL/SQL の言語要素 13-151

Page 560: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RESTRICT_REFERENCES プラグマ

使用上の注意使用上の注意使用上の注意使用上の注意

RESTRICT_REFERENCESプラグマは、パッケージ仕様部またはオブジェクト型仕様部でのみ宣言できます。制約は 4 つまで(RNDS、RNPS、WNDS、WNPS)任意の順序で指定できます。パラレル問合せからファンクションをコールするには、4 つの制約をすべて指定します。他の制約を暗黙的に指定する制約はありません。

TRUSTを指定すると、ファンクション本体はプラグマにリストされた制約に違反しているかどうかチェックされません。ファンクションは制約に違反していないことを承認されます。これらのチェックをスキップすると、パフォーマンスが向上します。

サブプログラム名ではなく DEFAULTを指定した場合、このプラグマはパッケージ仕様部またはオブジェクト型の仕様部(オブジェクト型のシステム定義のコンストラクタも含む)の中のすべてのサブプログラムに適用されます。その場合でも、サブプログラムごとにプラグマを宣言し、デフォルトのプラグマをオーバーライドできます。

RESTRICT_REFERENCESプラグマは、1 つのサブプログラム宣言にのみ適用できます。オーバーロードされたサブプログラムの名前を参照するプラグマは、直前のサブプログラム宣言に必ず適用されます。

通常、このプラグマはファンクションにのみ指定します。ファンクションがプロシージャをコールする場合は、それらのプロシージャにも同様にプラグマを指定する必要があります。

例例例例

次の例では、ファンクション BALANCEがデータベースへの書込み禁止状態(WNDS)およびパッケージに読込み禁止状態(RNPS)であることを示します。したがって、このファンクションは DDL 文や DML 文を発行せず、パッケージ変数も参照せず、コールしたプロシージャやファンクションも実行しません。ただし、問合せを発行したり、パッケージ変数に値を代入する場合があります。

CREATE PACKAGE loans AS FUNCTION balance(account NUMBER) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES (balance, WNDS, RNPS);END loans;/

DROP PACKAGE loans;

関連項目関連項目関連項目関連項目

AUTONOMOUS_TRANSACTION プラグマ、EXCEPTION_INIT プラグマ、SERIALLY_REUSABLE プラグマ

13-152 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 561: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RETURN 文

RETURN 文文文文

RETURN文は、サブプログラムの実行を即座に完了させ、コール元に制御を戻します。その後は、サブプログラム・コールの直後の文から、実行が再開されます。ファンクションの中の RETURN文は、ファンクション識別子を戻り値に代入します。詳細は、8-6 ページの

「RETURN 文の使用」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

expression変数、定数、リテラル、演算子、ファンクション・コールの組合せです。 も単純な式は、1 個の変数で構成されています。RETURN文を実行すると、expressionの値がファンクション識別子に代入されます。

使用上の注意使用上の注意使用上の注意使用上の注意

RETURN文を、ファンクションの仕様部の中で戻り値のデータ型を指定する RETURN句と混同しないようにしてください。

サブプログラムでは、複数の RETURN文を使用できます。どの RETURN 文を実行しても、サブプログラムは即座に終了します。RETURN 文をサブプログラムの 後の文として配置する必要はありません。

プロシージャでは、RETURN文に式を含めることはできません。RETURN 文には、プロシージャ本来の終了地点に達する前に、コール元に制御を戻す役割のみがあります。

ファンクションでは、RETURN文に、RETURN文の実行時に評価される式が含まれている必要があります。結果として得られる値がファンクション識別子に代入されます。ファンクションには、RETURN文へ導く少なくとも 1 つの実行パスが必要です。そうではない場合、PL/SQL によって実行時に例外が呼び出されます。

RETURN文を無名ブロックで使用して、そのブロック(およびすべての外側のブロック)を終了させることができますが、RETURN文は式を含むことはできません。

RETURN

(expression

)

;

return_statement

PL/SQL の言語要素 13-153

Page 562: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

RETURN 文

例例例例

次の例では、変数や式を使用した場合または引数なしの場合の RETURN文を示します。

DECLARE FUNCTION num_rows (table_name VARCHAR2) RETURN user_tables.num_rows%TYPE IS howmany user_tables.num_rows%TYPE; BEGIN EXECUTE IMMEDIATE 'SELECT num_rows FROM user_tables ' || 'WHERE table_name = ''' || UPPER(table_name) || '''' INTO howmany;-- A function can compute a value, then return that value. RETURN howmany; END num_rows;

FUNCTION double_it(n NUMBER) RETURN NUMBER IS BEGIN-- A function can also return an expression. RETURN n * 2; END double_it;

PROCEDURE print_something IS BEGIN dbms_output.put_line('Message 1.');-- A procedure can end early by issuing RETURN with no value. RETURN; dbms_output.put_line('Message 2 (never printed).'); END;BEGIN dbms_output.put_line('EMPLOYEES has ' || num_rows('employees') || ' rows.'); dbms_output.put_line('Twice 100 is ' || double_it(n => 100) || '.'); print_something;END;/

関連項目関連項目関連項目関連項目

ファンクション、プロシージャ

13-154 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 563: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ROLLBACK 文

ROLLBACK 文文文文

ROLLBACK文は COMMIT文の逆です。これは、カレント・トランザクションでデータベースに加えられたすべての変更または一部の変更を取り消します。詳細は、6-38 ページの

「PL/SQL におけるトランザクション処理の概要」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

ROLLBACKパラメータなしの ROLLBACK文が実行されると、カレント・トランザクションでデータベースに加えられた変更がすべて取り消されます。

ROLLBACK TOsavepoint_nameで識別されるセーブポイントがマークされた後にデータベースに加えられた変更をすべて取り消します(また、マーク以降に取得されたロックをすべて解放します)。

SAVEPOINT見やすくする目的でのみ使用するオプションです。

savepoint_nameトランザクション処理の中で現行の位置を識別するためのマークとなる未宣言の識別子です。ネーミング規則は、2-4 ページの「識別子」を参照してください。

WORK見やすくする目的でのみ使用するオプションです。

ROLLBACKWORK TO

SAVEPOINTsavepoint_name

;

rollback_statement

PL/SQL の言語要素 13-155

Page 564: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ROLLBACK 文

使用上の注意使用上の注意使用上の注意使用上の注意

ロールバック先のセーブポイント以降にマークされているセーブポイントはすべて消去されます。ロールバック先のセーブポイントは消去されません。たとえば、セーブポイントをA、B、C、D の順でマークしている場合、セーブポイント B までロールバックすると、セーブポイント C と D のみが消去されます。

INSERT文、UPDATE文または DELETE文を実行する前に、暗黙的なセーブポイントがマークされます。文の実行が失敗すると、その暗黙的なセーブポイントまでロールバックされます。通常は、トランザクション全体ではなく、失敗した SQL 文のみがロールバックされます。その文が原因で未処理例外が呼び出された場合は、ホスト環境によってロールバックの対象が決まります。

SQL では、FORCE句はインダウト分散トランザクションを手動でロールバックする句です。PL/SQL ではこの句はサポートされていません。たとえば、次の宣言は誤りです。

ROLLBACK WORK FORCE '24.37.85'; -- not allowed

埋込み SQL では、RELEASEオプションは、プログラムに保持されるすべての Oracle リソース(ロックおよびカーソル)を解放し、データベースから切断します。PL/SQL ではこのオプションはサポートされていません。たとえば、次の宣言は誤りです。

ROLLBACK WORK RELEASE; -- not allowed

関連項目関連項目関連項目関連項目

COMMIT 文、SAVEPOINT 文

13-156 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 565: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

%ROWTYPE 属性

%ROWTYPE 属性属性属性属性

%ROWTYPE属性は、データベース表の中の行を表すレコード型を提供します。レコードには、表から選択された行全体、あるいはカーソルまたはカーソル変数でフェッチされた行全体のデータを格納できます。レコード中のフィールドと、それに対応する行の中の列は、同じ名前とデータ型を持ちます。

%ROWTYPE属性は、変数宣言の中でデータ型指定子として使用できます。%ROWTYPE属性を使用して宣言された変数は、データ型名を使用して宣言された変数と同じように扱われます。詳細は、2-14 ページの「%ROWTYPE 属性の使用」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

cursor_name現行の有効範囲の中で、事前に宣言されている明示カーソルを識別します。

cursor_variable_name現行の有効範囲の中で事前に宣言されている、強い型指定を持つ PL/SQL カーソル変数を識別します。

table_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要があるデータベースの表(またはビュー)を識別します。

cursor_name

cursor_variable_name

table_name

% ROWTYPE

rowtype_attribute

PL/SQL の言語要素 13-157

Page 566: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

%ROWTYPE 属性

使用上の注意使用上の注意使用上の注意使用上の注意

変数を table_name%ROWTYPE型として宣言すると、データベース表と PL/SQL 間でデータを送信する場合に便利です。列ごとに個別の変数を作成するのではなく、単一の変数を作成します。ユーザーはすべての列の名前を知る必要がありません。作成した変数名ではなく、列の実名を使用して、列を参照します。後で列が表に追加されたり、表から削除された場合も、変更なしでコードは正常に機能します。

レコード中のフィールドを参照するには、ドット表記法(record_name.field_name)を使用します。この方法では、一度に 1 つのフィールドに対して読取りまたは書込みを行うことができます。

レコードのすべてのフィールドに一度に値を代入するには、次の 2 つの方法があります。

� 1 番目の方法として、PL/SQL では、レコード全体の宣言が同じ表またはカーソルを参照している場合には、そのレコード全体の間で集計代入できます。

� 2 番目の方法では、SELECT文か FETCH文を使用して、レコードに列値のリストを代入します。列名の順番は宣言された順番です。%ROWTYPEに関連付けられたカーソルからフェッチされた選択項目は、単純名を持つ必要があります。また、選択項目が式の場合は別名を持つ必要があります。

例例例例

次の例では、%ROWTYPEを使用して 2 つのレコードを宣言しています。1 つ目のレコードには表から選択された行全体が格納されます。2 つ目のレコードには、表の列のサブセットを問い合せるカーソル c1からフェッチされた行が格納されます。この例では、表から単一の行を取り出してレコードに格納した後、表の一部の列の値をチェックします。

DECLARE emp_rec employees%ROWTYPE; my_empno employees.employee_id%TYPE := 100; CURSOR c1 IS SELECT department_id, department_name, location_id FROM departments; dept_rec c1%ROWTYPE;BEGIN SELECT * INTO emp_rec FROM employees WHERE employee_id = my_empno; IF (emp_rec.department_id = 20) AND (emp_rec.salary > 2000) THEN NULL; END IF;END;/

関連項目関連項目関連項目関連項目

定数と変数、カーソル、カーソル変数、FETCH 文

13-158 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 567: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SAVEPOINT 文

SAVEPOINT 文文文文

SAVEPOINT文は、トランザクション処理の過程で、現行の位置に名前を付けてマークします。セーブポイントを ROLLBACK TO文と組み合せると、トランザクション全体ではなく、トランザクションの一部を取り消すことができます。詳細は、6-38 ページの「PL/SQL におけるトランザクション処理の概要」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

savepoint_nameトランザクション処理の中で現行の位置を識別するためのマークとなる未宣言の識別子です。

使用上の注意使用上の注意使用上の注意使用上の注意

単純なロールバックまたはコミットではすべてのセーブポイントが消去されます。あるセーブポイントまでロールバックすると、そのセーブポイント以降にマークされたセーブポイントはすべて消去されます。ロールバック先のセーブポイントは消去されません。

セーブポイント名は、トランザクション内で再利用できます。再利用すると、セーブポイントはトランザクションの中の古い位置から現在の位置に移動します。

再帰的サブプログラムの中でセーブポイントをマークすると、再帰しながら進む過程で、各レベルで SAVEPOINT文の新しいインスタンスが実行されます。ロールバックできるのは直前にマークされたセーブポイントまでのみです。

INSERT文、UPDATE文または DELETE文を実行する前に、暗黙的なセーブポイントがマークされます。文の実行が失敗すると、その暗黙的なセーブポイントまでロールバックされます。通常は、トランザクション全体ではなく、失敗した SQL 文のみがロールバックされます。その文が原因で未処理例外が呼び出された場合は、ホスト環境(SQL*Plus など)によってロールバックの対象が決まります。

関連項目関連項目関連項目関連項目

COMMIT 文、ROLLBACK 文

SAVEPOINT savepoint_name ;

savepoint_statement

PL/SQL の言語要素 13-159

Page 568: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SCN_TO_TIMESTAMP ファンクション

SCN_TO_TIMESTAMP ファンクションファンクションファンクションファンクション

構文構文構文構文return_value := SCN_TO_TIMESTAMP(number);

用途用途用途用途

SCN_TO_TIMESTAMPは、システム変更番号(SCN)を表す引数を取り、その SCN に関連付けられたタイムスタンプを戻します。戻り値のデータ型は TIMESTAMPです。

使用上の注意使用上の注意使用上の注意使用上の注意

このファンクションは、フラッシュバック問合せ機能の一部です。システム変更番号によって、ある時点のデータベースの状態を正確に指定することができるため、ユーザーはその時点のデータを確認できます。

このファンクションをコールすると、フラッシュバック問合せで使用する格納済の SCN に関連付けられた日付と時刻を確認できます。

例例例例DECLARE right_now TIMESTAMP; yesterday TIMESTAMP; sometime TIMESTAMP; scn1 INTEGER; scn2 INTEGER; scn3 INTEGER;BEGIN-- Get the current SCN. right_now := SYSTIMESTAMP; scn1 := TIMESTAMP_TO_SCN(right_now); dbms_output.put_line('Current SCN is ' || scn1);

-- Get the SCN from exactly 1 day ago. yesterday := right_now - 1; scn2 := TIMESTAMP_TO_SCN(yesterday); dbms_output.put_line('SCN from yesterday is ' || scn2);

-- Find an arbitrary SCN somewhere between yesterday and today.-- (In a real program we would have stored the SCN at some significant moment.) scn3 := (scn1 + scn2) / 2;-- Find out what time that SCN was in effect. sometime := SCN_TO_TIMESTAMP(scn3); dbms_output.put_line('SCN ' || scn3 || ' was in effect at ' || TO_CHAR(sometime));END;/

13-160 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 569: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SCN_TO_TIMESTAMP ファンクション

関連項目関連項目関連項目関連項目

TIMESTAMP_TO_SCN ファンクション

PL/SQL の言語要素 13-161

Page 570: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SELECT INTO 文

SELECT INTO 文文文文

SELECT INTO文は、データベースの 1 つ以上の表からデータを取り出して、選択した値を変数またはコレクションに代入します。SELECT文の詳細は、『Oracle Database SQL リファレンス』を参照してください。

デフォルトの使用方法(SELECT ... INTO)では、この文は単一の行から 1 つ以上の列を取り出します。バルクでの使用方法(SELECT ... BULK COLLECT INTO)では、この文は結果セット全体を一度に取り出します。

構文構文構文構文

SELECT

*

select_item

,

select_into_statement

INTOvariable_name

,

record_name

BULK COLLECT INTOcollection_name

: host_array_name

,

FROMalias

,

rest_of_statement ;( subquery

TABLE ( subquery2 )

table_reference

)

DISTINCT

UNIQUE

ALL

13-162 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 571: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SELECT INTO 文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

alias参照される列、表またはビューの別名(通常は短縮名)です。

BULK COLLECT1 つ以上のコレクションに結果の値を格納します。FETCH文を使用したループよりも高速な問合せが可能です。詳細は、11-9 ページの「DML 文および問合せのループ・オーバーヘッドの削減(FORALL および BULK COLLECT)」を参照してください。

collection_nameフェッチした select_item値を格納するための、宣言されたコレクションを識別します。select_itemごとに、リストの中に、対応する型互換のコレクションが存在している必要があります。

function_nameユーザー定義のファンクションを識別します。

function_name( parameter_name

,

)

NULL

numeric_literal

schema_name . table_name

view_name. *

schema_name . table_name

view_name.

column_name

sequence_name .CURRVAL

NEXTVAL

' text '

ASalias

select_item

PL/SQL の言語要素 13-163

Page 572: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SELECT INTO 文

host_array_nameフェッチした select_item値を格納するための配列を識別します。この配列は、PL/SQLホスト環境で宣言され、バインド変数として PL/SQL に渡されます。select_itemごとに、リストの中に、対応する型互換の配列が存在している必要があります。ホスト配列には、接頭辞としてコロンが必要です。

numeric_literal数値または暗黙的に数値に変換可能な値を表すリテラルです。

parameter_nameユーザー定義ファンクションの仮パラメータを識別します。

record_nameフェッチした行の値を格納する、ユーザー定義のレコードまたは %ROWTYPEレコードを識別します。問合せが戻す select_item値に対して、レコードの中に、対応する型互換のフィールドが存在している必要があります。

rest_of_statementSAMPLE句を除く、SQL の SELECT文の FROM句に続けることができる任意の構造体です。

schema_name表またはビューが含まれているスキーマを識別します。schema_nameを省略すると、表またはビューはユーザーのスキーマ内に存在するとみなされます。

subquery処理する行セットを提供する SELECT文です。構文は select_into_statementの構文と似ていますが、INTO句は使用できません。13-162 ページの「SELECT INTO 文」を参照してください。

table_reference表またはビューを指定します。指定された表またはビューは、SELECT文の実行時にアクセスできる必要があり、ユーザーは SELECT権限を持っている必要があります。table_referenceの構文は、13-57 ページの「DELETE 文」を参照してください。

TABLE (subquery2)TABLEのオペランドは、1 つの列値を戻す SELECT文です。これはネストした表またはVARRAY である必要があります。演算子 TABLEは、値がスカラー値ではなくコレクションであることを Oracle に通知します。

13-164 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 573: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SELECT INTO 文

variable_nameフェッチした select_item値を格納するための、事前に宣言された変数を識別します。問合せが戻す select_item値に対して、リストの中に、対応する型互換の変数が存在している必要があります。

使用上の注意使用上の注意使用上の注意使用上の注意

デフォルトでは、SELECT INTO文は 1 行のみを戻す必要があります。それ以外の場合、PL/SQL は事前定義の例外 TOO_MANY_ROWSを呼び出して、INTO句内の変数の値は未定義になります。WHERE句が 1 行とのみ一致するように指定してください。

行が戻されなかった場合は、PL/SQL によって NO_DATA_FOUNDが呼び出されます。可能な場合、COUNT(*)、AVG()などの集計関数の結果を選択すると、この例外を回避できます。これらの集計関数は、条件に一致する行がない場合でも、必ず単一の値を戻します。

SELECT ... BULK COLLECT INTO文を使用すると、複数行を戻すことができます。結果を保持するようにコレクション変数を設定する必要があります。必要に応じて、拡張される結合配列またはネストした表を宣言して、結果セット全体を保持することもできます。

暗黙カーソル SQLとカーソル属性 %NOTFOUND、%FOUND、%ROWCOUNTおよび %ISOPENを使用すると、SELECT INTO文の実行についての情報が得られます。

例例例例

次の例では、SELECT INTO文を使用して、単一の値を問い合せて PL/SQL 変数に代入します。さらに、列全体を問い合せて PL/SQL コレクションに代入したり、行全体を問い合せてレコードの PL/SQL コレクションに代入します。

DECLARE howmany NUMBER; some_first employees.first_name%TYPE; some_last employees.last_name%TYPE; some_employee employees%ROWTYPE; TYPE first_typ IS TABLE OF employees.first_name%TYPE INDEX BY PLS_INTEGER; TYPE last_typ IS TABLE OF employees.first_name%TYPE INDEX BY PLS_INTEGER; first_names first_typ; last_names last_typ; CURSOR c1 IS SELECT first_name, last_name FROM employees; TYPE name_typ IS TABLE OF c1%ROWTYPE INDEX BY PLS_INTEGER; all_names name_typ; TYPE emp_typ IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER; all_employees emp_typ;BEGIN-- Query a single value and store it in a variable. SELECT COUNT(*) INTO howmany FROM user_tables; dbms_output.put_line('This schema owns ' || howmany || ' tables.');

-- Query multiple columns from one row, and store them in variables.

PL/SQL の言語要素 13-165

Page 574: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SELECT INTO 文

SELECT first_name, last_name INTO some_first, some_last FROM employees WHERE ROWNUM < 2; dbms_output.put_line('Random employee: ' || some_first || ' ' || some_last);

-- Query a single row and store it in a record. SELECT * INTO some_employee FROM employees WHERE ROWNUM < 2;

-- Query multiple columns from multiple rows, and store them in a collection-- of records. SELECT first_name, last_name BULK COLLECT INTO all_names FROM EMPLOYEES;

-- Query multiple columns from multiple rows, and store them in separate-- collections. (Generally less useful than a single collection of records.) SELECT first_name, last_name BULK COLLECT INTO first_names, last_names FROM EMPLOYEES;

-- Query an entire (small!) table and store the rows-- in a collection of records. Now you can manipulate the data-- in-memory without any more I/O. SELECT * BULK COLLECT INTO all_employees FROM employees;END;/

関連項目関連項目関連項目関連項目

代入文、FETCH 文、%ROWTYPE 属性

13-166 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 575: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SERIALLY_REUSABLE プラグマ

SERIALLY_REUSABLE プラグマプラグマプラグマプラグマ

SERIALLY_REUSABLEプラグマは、サーバーへの 1 コール(無名 PL/SQL ブロック、データベースへの OCI コール、データベース・リンクを介したストアド・プロシージャ・コールなど)の間のみ、そのパッケージの状態が必要であることを示します。このコールの後、パッケージ変数の記憶域の再利用が可能になり、長時間実行セッションのメモリー・オーバーヘッドが削減されます。詳細は、『Oracle Database アプリケーション開発者ガイド - 基礎編』を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

PRAGMA文がプラグマ(コンパイラ・ディレクティブ)であることを表します。プラグマは、実行時ではなくコンパイル時に処理されます。プログラムの機能に影響を与えず、コンパイラに情報を提供する役割のみです。

使用上の注意使用上の注意使用上の注意使用上の注意

このプラグマは、同じセッションのそれ以降のデータベース・コール中には必要ない、1 回のみ使用される大規模な一時作業領域を宣言するパッケージに適しています。

本体部のないパッケージを逐次再使用可能としてマークできます。パッケージに仕様部と本体がある場合は、両方ともマークする必要があります。本体のみをマークすることはできません。

逐次再使用可能なパッケージのグローバル・メモリーは、ユーザー・グローバル領域(UGA)で個々のユーザーに割り当てられるのではなく、システム・グローバル領域(SGA)にプールされます。それによって、パッケージ作業領域の再使用が可能になります。サーバーへのコールが終わると、メモリーはプールに戻されます。パッケージが再使用されるたびに、そのパッケージのパブリック変数はデフォルト値か NULLに初期設定されます。

逐次再使用可能パッケージには、データベース・トリガー、または SQL 文からコールされる他の PL/SQL サブプログラムからアクセスすることはできません。これを試行すると、Oracle はエラーを生成します。

PRAGMA SERIALLY_REUSABLE ;

serially_reusable_pragma

PL/SQL の言語要素 13-167

Page 576: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SERIALLY_REUSABLE プラグマ

例例例例

次の例では、逐次再使用可能パッケージを作成します。

CREATE PACKAGE pkg1 IS PRAGMA SERIALLY_REUSABLE; num NUMBER := 0; PROCEDURE init_pkg_state(n NUMBER); PROCEDURE print_pkg_state;END pkg1;/

CREATE PACKAGE BODY pkg1 IS PRAGMA SERIALLY_REUSABLE; PROCEDURE init_pkg_state (n NUMBER) IS BEGIN pkg1.num := n; END; PROCEDURE print_pkg_state IS BEGIN dbms_output.put_line('Num: ' || pkg1.num); END;END pkg1;/

DROP PACKAGE pkg1;

関連項目関連項目関連項目関連項目

AUTONOMOUS_TRANSACTION プラグマ、EXCEPTION_INIT プラグマ、RESTRICT_REFERENCES プラグマ

13-168 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 577: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SET TRANSACTION 文

SET TRANSACTION 文文文文

SET TRANSACTION文は、読取り専用または読取り / 書込みのトランザクションを開始するか、分離レベルを設定するか、指定したロールバック・セグメントにカレント・トランザクションを代入します。読取り専用トランザクションは、他のユーザーが更新中である 1 つ以上の表に対して、複数の問合せを実行する場合に便利です。詳細は、6-41 ページの「SET TRANSACTION を使用したトランザクション・プロパティの設定」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

READ ONLYカレント・トランザクションを読取り専用に設定する句です。これによって、それ以降の問合せからはトランザクションの開始前にコミットされた変更内容のみが参照されます。READ ONLYを使用しても、他のユーザーや他のトランザクションには影響がありません。

READ WRITEカレント・トランザクションを読取り / 書込みに設定する句です。READ WRITEを使用しても、他のユーザーや他のトランザクションには影響がありません。トランザクションでDML 文が実行されると、Oracle はトランザクションをロールバック・セグメントに代入します。

ISOLATION LEVELデータベースを変更するトランザクションがどのように処理されるかを指定します。

SERIALIZABLE: 直列可能トランザクションが、コミットされていない別のトランザクションですでに変更された表を変更する SQL DML 文を実行しようとした場合、その文は失敗します。

SET TRANSACTION

READ ONLY

READ WRITE

ISOLATION LEVELSERIALIZABLE

READ COMMITTED

USE ROLLBACK SEGMENT rollback_segment

NAME ’text’;

PL/SQL の言語要素 13-169

Page 578: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SET TRANSACTION 文

SERIALIZABLEモードを使用可能にするには、DBA が、Oracle 初期化パラメータCOMPATIBLEを 7.3.0 以上に設定します。

READ COMMITTED: トランザクションに含まれる SQL DML 文が、別のトランザクションによって保持されている行ロックを必要とする場合に、その文は行ロックが解放されるまで待機します。

USE ROLLBACK SEGMENTカレント・トランザクションを指定したロールバック・セグメントに代入し、トランザクションを読取り / 書込みに設定する句です。このパラメータは、同じトランザクションの中で READ ONLYパラメータとともには使用できません。読取り専用トランザクションは、ロールバック情報を生成しないためです。

NAMEトランザクションの名前またはコメント・テキストを指定します。この指定した名前やコメント・テキストはトランザクションの実行中に使用可能で、長時間実行のインダウト・トランザクションをモニターしやすくなるため、COMMIT COMMENT機能を使用するより適切です。

使用上の注意使用上の注意使用上の注意使用上の注意

SET TRANSACTION文は、トランザクションの 初の SQL 文にする必要があり、そのトランザクションで 1 回しか使用できません。

例例例例

次の例では、読取り専用トランザクションを確立しています。

BEGIN COMMIT; -- end previous transaction SET TRANSACTION READ ONLY; FOR person IN (SELECT last_name FROM employees WHERE ROWNUM < 10) LOOP dbms_output.put_line(person.last_name); END LOOP; dbms_output.put_line('------------------'); FOR dept IN (SELECT department_name FROM departments WHERE ROWNUM < 10) LOOP dbms_output.put_line(dept.department_name); END LOOP; COMMIT; -- end read-only transactionEND;/

13-170 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 579: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SET TRANSACTION 文

関連項目関連項目関連項目関連項目

COMMIT 文、ROLLBACK 文、SAVEPOINT 文

PL/SQL の言語要素 13-171

Page 580: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL カーソル

SQL カーソルカーソルカーソルカーソル

明示カーソルに関連付けられていない SQL 文を処理するために、Oracle は暗黙的にカーソルをオープンします。PL/SQL では直前の暗黙カーソルを SQLカーソルとして参照できます。SQL カーソルには、%FOUND、%ISOPEN、%NOTFOUNDおよび %ROWCOUNTの 4 つの属性があります。これらの属性を使用すると、DML 文の実行についての情報が得られます。SQLカーソルには、FORALL文で使用できるように設計された追加の属性%BULK_ROWCOUNTおよび %BULK_EXCEPTIONSもあります。詳細は、6-11 ページの

「PL/SQL を使用したデータの問合せ」を参照してください。

構文構文構文構文

SQL %

FOUND

ISOPEN

NOTFOUND

ROWCOUNT

BULK_ROWCOUNT ( index )

BULK_EXCEPTIONS ( index ) .ERROR_INDEX

ERROR_CODE

13-172 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 581: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL カーソル

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

%BULK_ROWCOUNTFORALL文で使用するために設計された複合属性です。この属性は索引付き表のように取り扱われます。i 番目の要素には、UPDATE文または DELETE文の i 番目の実行によって処理された行の数が格納されます。i 番目の実行によって影響を受ける行がない場合、%BULK_ROWCOUNT(i)は 0(ゼロ)を戻します。

%BULK_EXCEPTIONSSAVE EXCEPTIONS句を使用する FORALL文によって発生した例外についての情報を格納する結合配列です。この要素をループして、例外の発生した箇所と内容を判断する必要があります。SQL%BULK_EXCEPTIONS(i).ERROR_INDEXは、1 からSQL%BULK_EXCEPTIONS.COUNTまでの各索引値 iにおいて、例外の原因となった FORALLループの反復を指定します。SQL%BULK_EXCEPTIONS(i).ERROR_CODEは、例外に対応する Oracle エラー・コードを指定します。

%FOUNDINSERT文、UPDATE文または DELETE文が 1 つ以上の行に影響を与える場合またはSELECT INTO文が 1 つ以上の行を戻す場合、この属性は TRUEを戻します。それ以外の場合は、FALSEを戻します。

%ISOPENOracle は、SQLカーソルに関連付けられた SQL 文の実行を終了すると、このカーソルを自動的にクローズするため、この属性は常に FALSEを戻します。

%NOTFOUND%FOUNDとは論理的に反対の意味を持ちます。INSERT文、UPDATE文または DELETE文がどの行にも影響を与えない場合または SELECT INTO文がどの行も戻さない場合、この属性は TRUEを戻します。それ以外の場合は、FALSEを戻します。

%ROWCOUNTINSERT文、UPDATE文または DELETE文に影響を受けた行、または SELECT INTO文に戻された行の数を戻します。

SQLOracle 暗黙カーソルの名前です。

PL/SQL の言語要素 13-173

Page 582: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL カーソル

使用上の注意使用上の注意使用上の注意使用上の注意

カーソル属性は、プロシージャ文では使用できますが、SQL 文では使用できません。Oracleが SQLカーソルを自動的にオープンするまでは、暗黙カーソルの属性は NULLを戻します。

カーソル属性の値は、常に直前に実行された SQL 文を参照します(その文の場所とは無関係です)。文が別の有効範囲に存在する場合もあります。したがって、属性の値を保存して後で使用する場合は、ブール変数にただちに代入してください。

SELECT INTO文が行を戻せなかった場合は、次の行で SQL%NOTFOUNDをチェックしているかどうかにかかわらず、PL/SQL によって事前定義済の例外 NO_DATA_FOUNDが呼び出されます。SQL 集計関数をコールする SELECT INTO文が、NO_DATA_FOUNDを呼び出すことはありません。SQL 集計関数は、必ず値または NULL を戻します。このような場合、SQL%NOTFOUNDは FALSEを戻します。

%BULK_ROWCOUNTは、冗長になるのを防ぐためバルク挿入用に保持されません。たとえば、次の FORALL文は反復ごとに 1 つの行を挿入します。反復するたびに %BULK_ROWCOUNTは1 を戻します。

CREATE TABLE num_table (n NUMBER);

DECLARE TYPE NumList IS TABLE OF NUMBER; nums NumList := NumList(1,3,5,7,11,13,17);BEGIN FORALL i IN nums.FIRST .. nums.LAST INSERT INTO num_table (n) VALUES (nums(i));

FOR i IN nums.FIRST .. nums.LAST LOOP dbms_output.put_line('Inserted ' || SQL%BULK_ROWCOUNT(i) || ' row(s)' || ' on iteration ' || i); END LOOP;END;/

DROP TABLE num_table;

バルク・バインドには、スカラー属性の %FOUND、%NOTFOUNDおよび %ROWCOUNTを使用できます。たとえば、%ROWCOUNTは、SQL 文のすべての実行によって処理された行の総数を戻します。

%FOUNDと %NOTFOUNDは、SQL 文の 後の実行のみを参照しますが、%BULK_ROWCOUNTを使用すると、個々の実行に対する値を推論できます。たとえば、%BULK_ROWCOUNT(i)が 0(ゼロ)の場合、%FOUNDと %NOTFOUNDはそれぞれ、FALSEおよび TRUEになります。

13-174 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 583: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL カーソル

例例例例

次の例では、更新される行がない場合にのみ新しい行を挿入します。

CREATE TABLE visitors (email VARCHAR2(128), pages_visited INTEGER DEFAULT 1);

CREATE OR REPLACE PROCEDURE someone_visited (visitor_email visitors.email%TYPE)ASBEGIN UPDATE visitors SET pages_visited = pages_visited + 1 WHERE email = visitor_email; IF SQL%NOTFOUND THEN INSERT INTO visitors (email) VALUES (visitor_email); dbms_output.put_line('Adding ' || visitor_email || ' to the table.'); ELSE dbms_output.put_line('Incremented counter for ' || visitor_email || '.'); END IF;END;/

DECLARE visitor_email visitors.email%TYPE := 'fred@fictional_domain.com';BEGIN someone_visited(visitor_email); someone_visited(visitor_email);END;/

DROP TABLE visitors;DROP PROCEDURE someone_visited;

次の例では、10 を超える行数が削除された場合に例外を呼び出します。

CREATE TABLE temp AS SELECT object_name name FROM user_objects;

DECLARE large_deletion EXCEPTION; rows_deleted NUMBER;BEGIN DELETE FROM temp WHERE name LIKE '%A%'; rows_deleted := SQL%ROWCOUNT; COMMIT; IF rows_deleted > 10 THEN RAISE large_deletion; END IF;

dbms_output.put_line('Nothing unusual detected.');

PL/SQL の言語要素 13-175

Page 584: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL カーソル

EXCEPTION WHEN large_deletion THEN dbms_output.put_line('Recording deletion of ' || rows_deleted || ' rows in case of error.');END;/

DROP TABLE temp;

次の例では、%BULK_ROWCOUNTを使用します。FORALL文の完了後に、3 番目の UPDATEによって更新された行数がチェックされます。

CREATE TABLE num_table (n NUMBER);

DECLARE TYPE NumList IS TABLE OF NUMBER; nums NumList := NumList(1,3,5,5,11,5,5);BEGIN FORALL i IN nums.FIRST .. nums.LAST INSERT INTO num_table (n) VALUES (nums(i));

-- All the numbers in the table will be squared.-- Some updates will affect more rows than others. FORALL j IN nums.FIRST .. nums.LAST UPDATE num_table SET n = n * n WHERE n = nums(j);

FOR k IN nums.FIRST .. nums.LAST LOOP dbms_output.put_line('Update #' || k || ' affected ' || SQL%BULK_ROWCOUNT(k) || ' rows.'); END LOOP;END;/

DROP TABLE num_table;

関連項目関連項目関連項目関連項目

カーソル、カーソル属性、FORALL 文、11-17 ページの「%BULK_EXCEPTIONS 属性を持つ FORALL 例外の処理」

13-176 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 585: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQLCODE ファンクション

SQLCODE ファンクションファンクションファンクションファンクション

SQLCODEファンクションは、直前の例外の番号コードを戻します。

内部例外の場合、SQLCODEは関連付けられている Oracle エラーの番号を戻します。SQLCODEが戻す番号は負の値ですが、Oracle エラー「データが見つかりません。」の場合は例外です。この場合、SQLCODEは +100を戻します。

ユーザー定義の例外の場合、SQLCODEは +1を戻します。ただし、EXCEPTION_INITプラグマを使用して例外を Oracle エラー番号に関連付けている場合は、代入した値を戻します。

構文構文構文構文

使用上の注意使用上の注意使用上の注意使用上の注意

SQLCODEは例外ハンドラの中でのみ有効です。ハンドラの外側では、SQLCODEは常に 0を戻します。SQLCODEは呼び出された内部例外の識別に使用できるため、OTHERS例外ハンドラの中で使用すると特に便利です。

SQLCODEは、SQL 文の中で直接使用することができません。まず、SQLCODEの値をローカル変数に代入します。

RESTRICT_REFERENCESプラグマを使用してストアド・ファンクションの純正度を示すときにファンクションが SQLCODEをコールする場合は、WNPSおよび RNPS制約は指定できません。

SQLCODE

sqlcode_function

PL/SQL の言語要素 13-177

Page 586: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQLCODE ファンクション

例例例例

次の例では、SQLCODEの値を監査表に挿入します。

CREATE TABLE errors (code NUMBER, message VARCHAR2(128), happened TIMESTAMP);DECLARE name employees.last_name%TYPE; my_code NUMBER; my_errm VARCHAR2(32000);BEGIN SELECT last_name INTO name FROM employees WHERE employee_id = -1; EXCEPTION WHEN OTHERS THEN my_code := SQLCODE; my_errm := SQLERRM; dbms_output.put_line('Error code ' || my_code || ': ' || my_errm);-- Normally we would call another procedure, declared with PRAGMA-- AUTONOMOUS_TRANSACTION, to insert information about errors. INSERT INTO errors VALUES (my_code, my_errm, SYSTIMESTAMP);END;/DROP TABLE errors;

関連項目関連項目関連項目関連項目

例外、SQLERRM ファンクション、10-19 ページの 「エラー・コードとエラー・メッセージの取得 : SQLCODE および SQLERRM」

13-178 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 587: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQLERRM ファンクション

SQLERRM ファンクションファンクションファンクションファンクション

SQLERRMファンクションは、エラー番号の引数に関連付けられているエラー・メッセージを戻します。引数が省略されている場合は、SQLCODEのカレント値に関連付けられているエラー・メッセージを戻します。引数なしの SQLERRMは、例外ハンドラの中でのみ有効です。ハンドラの外側では、引数なしの SQLERRMは常にメッセージ「正常に完了しました。」を戻します。

内部例外の場合、SQLERRMは、発生した Oracle エラーに関連付けられているメッセージを戻します。メッセージの先頭には Oracle エラー・コードが示されています。

ユーザー定義の例外の場合、SQLERRMはメッセージ「ユーザー定義の例外」を戻します。ただし、EXCEPTION_INITプラグマを使用して例外を Oracle エラー番号に関連付けている場合は例外です。この場合、SQLERRMは対応するエラー・メッセージを戻します。詳細は、10-19 ページの「エラー・コードとエラー・メッセージの取得 : SQLCODE およびSQLERRM」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

error_number有効な Oracle エラー番号です。Oracle エラー(接頭辞として ORA- が付くエラー)のリストは、『Oracle Database エラー・メッセージ』を参照してください。

使用上の注意使用上の注意使用上の注意使用上の注意

SQLERRMは呼び出された内部例外の識別に使用できるため、OTHERS例外ハンドラの中で使用すると特に便利です。

SQLERRMに渡されるエラー番号は、負の値です。0(ゼロ)を渡すと、SQLERRMは常に次のメッセージを戻します。

ORA-0000: 正常に完了しました。

正数を渡すと、SQLERRMは常に次のメッセージを戻します。

User-Defined Exception

SQLERRM( error_number )

sqlerrm_function

PL/SQL の言語要素 13-179

Page 588: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQLERRM ファンクション

ただし、+100を渡した場合、SQLERRMは次のメッセージを戻します。

ORA-01403: データが見つかりません。

SQLERRMは、SQL 文の中で直接使用することができません。まず、SQLERRMの値をローカル変数に代入します。

my_sqlerrm := SQLERRM;...INSERT INTO errors VALUES (my_sqlerrm, ...);

RESTRICT_REFERENCESプラグマを使用してストアド・ファンクションの純正度を示すときに、ファンクションが SQLERRMをコールする場合は WNPSおよび RNPS制約を指定できません。

例例例例

次の例では、未処理例外に関連付けられたエラー・メッセージを取り出して、監査表に格納します。長すぎて表に格納できないメッセージは、SUBSTRファンクションによって切り捨てられます。

CREATE TABLE errors (code NUMBER, message VARCHAR2(128), happened TIMESTAMP);DECLARE name employees.last_name%TYPE; my_code NUMBER; my_errm VARCHAR2(32000);BEGIN SELECT last_name INTO name FROM employees WHERE employee_id = -1; EXCEPTION WHEN OTHERS THEN my_code := SQLCODE; my_errm := SQLERRM; dbms_output.put_line('Error code ' || my_code || ': ' || my_errm);-- Normally we would call another procedure, declared with PRAGMA-- AUTONOMOUS_TRANSACTION, to insert information about errors. INSERT INTO errors VALUES (my_code, my_errm, SYSTIMESTAMP);END;/DROP TABLE errors;

関連項目関連項目関連項目関連項目

例外、SQLCODE ファンクション

13-180 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 589: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

TIMESTAMP_TO_SCN ファンクション

TIMESTAMP_TO_SCN ファンクションファンクションファンクションファンクション

構文構文構文構文return_value := TIMESTAMP_TO_SCN(timestamp);

用途用途用途用途

TIMESTAMP_TO_SCNは、正確な時刻を表す引数を取り、その時点のデータベースのシステム変更番号(SCN)を戻します。戻り値のデータ型は NUMBERです。

使用上の注意使用上の注意使用上の注意使用上の注意

このファンクションは、フラッシュバック問合せ機能の一部です。システム変更番号によって、ある時点のデータベースの状態を正確に指定することができるため、ユーザーはその時点のデータを確認できます。

このファンクションをコールすると、フラッシュバックする日付と時刻に関連付けられたシステム変更番号を確認できます。

例例例例DECLARE right_now TIMESTAMP; yesterday TIMESTAMP; sometime TIMESTAMP; scn1 INTEGER; scn2 INTEGER; scn3 INTEGER;BEGIN-- Get the current SCN. right_now := SYSTIMESTAMP; scn1 := TIMESTAMP_TO_SCN(right_now); dbms_output.put_line('Current SCN is ' || scn1);

-- Get the SCN from exactly 1 day ago. yesterday := right_now - 1; scn2 := TIMESTAMP_TO_SCN(yesterday); dbms_output.put_line('SCN from yesterday is ' || scn2);

-- Find an arbitrary SCN somewhere between yesterday and today.-- (In a real program we would have stored the SCN at some significant moment.) scn3 := (scn1 + scn2) / 2;-- Find out what time that SCN was in effect. sometime := SCN_TO_TIMESTAMP(scn3); dbms_output.put_line('SCN ' || scn3 || ' was in effect at ' || TO_CHAR(sometime));END;/

関連項目関連項目関連項目関連項目

SCN_TO_TIMESTAMP ファンクション

PL/SQL の言語要素 13-181

Page 590: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

%TYPE 属性

%TYPE 属性属性属性属性

%TYPE属性を使用すると、型名をハードコードするかわりに、宣言内のフィールド、レコード、ネストした表、データベース列または変数のデータ型を使用できます。%TYPE属性は、定数、変数、フィールドまたはパラメータを宣言するときにデータ型指定子として使用できます。参照する型が変更されると、宣言は自動的に更新されます。これによって、たとえば、VARCHAR2列を長くする場合にコードを変更する必要がなくなります。詳細は、2-12ページの「%TYPE 属性の使用」を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

collection_name現行の有効範囲のうち、これより前の部分で宣言されているネストした表、索引付き表または VARRAY を指定します。

cursor_variable_name現行の有効範囲の中で事前に宣言されている PL/SQL カーソル変数を識別します。カーソル変数に代入できるのは、別のカーソル変数の値のみです。

db_table_name.column_name宣言が PL/SQL コンパイラによって処理されるときにアクセスできる必要がある表および列を識別します。

collection_name

cursor_variable_name

object_name

record_name. field_name

db_table_name . column_name

variable_name

% TYPE

type_attribute

13-182 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 591: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

%TYPE 属性

object_name現行の有効範囲のうち、これより前の部分で宣言されているオブジェクト型のインスタンスを識別します。

record_name現行の有効範囲のうち、これより前の部分で宣言されているユーザー定義のレコードまたは%ROWTYPEレコードです。

record_name.field_name現行の有効範囲のうち、これより前の部分で宣言されているユーザー定義のレコードまたは%ROWTYPEレコードのフィールドを識別します。

variable_name同じ有効範囲の中で事前に宣言されている変数を識別します。

使用上の注意使用上の注意使用上の注意使用上の注意

%TYPE属性は、データベース列を参照する変数、フィールドおよびパラメータを宣言する場合に特に便利です。列の長さや型が変更されても、コードは正常に機能します。

%TYPEを使用して宣言した項目には NOT NULL列制約は継承されません。

PL/SQL の言語要素 13-183

Page 592: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

%TYPE 属性

例例例例DECLARE-- We know that BUFFER2 and BUFFER3 will be big enough to hold-- the answers. If we have to increase the size of BUFFER1, the-- other variables will change size as well. buffer1 VARCHAR2(13) := 'abCdefGhiJklm'; buffer2 buffer1%TYPE := UPPER(buffer1); buffer3 buffer1%TYPE := LOWER(buffer1);

-- We know that this variable will be able to hold the contents-- of this table column. If the table is altered to make the-- column longer or shorter, this variable will change size as well. tname user_tables.table_name%TYPE;

-- %TYPE is great for subprogram parameters too, no need to-- recompile the subprogram if the table column changes. PROCEDURE print_table_name(the_name user_tables.table_name%TYPE) IS BEGIN dbms_output.put_line('Table = ' || the_name); END;BEGIN SELECT table_name INTO tname FROM user_tables WHERE ROWNUM < 2; print_table_name(tname);END;/

関連項目関連項目関連項目関連項目

定数と変数、%ROWTYPE 属性

13-184 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 593: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

UPDATE 文文文文

UPDATE文は、表またはビューの中の 1 行以上の行にある指定された列の値を変更します。UPDATE文の詳細は、『Oracle Database SQL リファレンス』を参照してください。

構文構文構文構文

キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明キーワードとパラメータの説明

alias参照される表またはビューの別名(通常は短縮名)で、WHERE句の中で頻繁に使用されます。

column_name更新する列(または更新する複数の列の中の 1 つ)です。これは参照される表またはビューの列の名前にしてください。column_nameリストでは同じ列名を繰り返して使用できません。UPDATE文の列名は、表またはビューの中と同じ順序で指定する必要はありません。

UPDATE ( subquery

TABLE ( )subquery2

aliastable_reference

)

SET

column_name =sql_expression

( )

( column_name

,

) = ( )

,

WHEREsearch_condition

CURRENT OF cursor_name returning_clause;

subquery3

subquery4

update_statement

SET

column_name =sql_expression

( subque )

( column_name

,

) = ( sub )

,

WHEREsearch_condition

CURRENT OF cursor_name returning_clause;

PL/SQL の言語要素 13-185

Page 594: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

returning_clause更新された行から値を戻します。そのため、後で行を SELECTで選択する必要がありません。取り出した列値は、変数かホスト変数、またはコレクションかホスト配列に代入できます。RETURNING句はリモートまたはパラレルでの更新には使用できません。文を実行しても行に影響がない場合、RETURNING句で指定した変数の値は未定義になります。returning_clauseの構文は、13-57 ページの「DELETE 文」を参照してください。

SET column_name = sql_expressionこの句は sql_expressionの値を、column_nameによって識別される列に代入します。sql_expressionの中で、更新される表の列が参照されている場合、参照は現在行の列が対象になります。古い列の値は、等号の右辺で使用されます。

SET column_name = (subquery3)subquery3でデータベースから取り出した値を、column_nameによって識別される列に代入します。この副問合せは、正確に 1 つの行と 1 つの列を戻す必要があります。

SET (column_name, column_name, ...) = (subquery4)subquery4でデータベースから取り出した値を、column_nameリストにある列に代入します。副問合せは、リストされている列すべてを含む 1 つの行のみを戻す必要があります。

副問合せによって戻された列値は、列リストの列に順番に代入されます。1 番目の値はリストの 1 番目の列に、2 番目の値はリストの 2 番目の列に、というように代入されます。

次の例では、従業員 ID は正しいが、名前が間違っている表を作成します。次に、相関問合せを含む UPDATE文を実行して、EMPLOYEES表から正しい名前を取り出し、新しい表で名前を修正します。

-- Create a table with all the right IDs, but messed-up names.CREATE TABLE e1 AS SELECT employee_id, UPPER(first_name) first_name, TRANSLATE(last_name,'aeiou','12345') last_name FROM employees;

BEGIN-- Display the first 5 names to show they're messed up. FOR person IN (SELECT * FROM e1 WHERE ROWNUM < 6) LOOP dbms_output.put_line(person.first_name || ' ' || person.last_name); END LOOP; UPDATE e1 SET (first_name, last_name) = (SELECT first_name, last_name FROM employees WHERE employee_id = e1.employee_id); dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows. ***');-- Display the first 5 names to show they've been fixed up.

13-186 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 595: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

FOR person IN (SELECT * FROM e1 WHERE ROWNUM < 6) LOOP dbms_output.put_line(person.first_name || ' ' || person.last_name); END LOOP;END;/

DROP TABLE e1;

sql_expression任意の有効な SQL の式です。詳細は、『Oracle Database SQL リファレンス』を参照してください。

subquery処理する行セットを提供する SELECT文です。構文は select_into_statementの構文と似ていますが、INTO句は使用できません。13-162 ページの「SELECT INTO 文」を参照してください。

table_reference表またはビューを指定します。指定された表またはビューは、UPDATE文の実行時にアクセスできる必要があり、ユーザーが UPDATE権限を持つ必要があります。table_referenceの構文は、13-57 ページの「DELETE 文」を参照してください。

TABLE (subquery2)TABLEのオペランドは、1 つの列値を戻す SELECT文です。これはネストした表またはVARRAY である必要があります。演算子 TABLEは、値がスカラー値ではなくコレクションであることを Oracle に通知します。

WHERE CURRENT OF cursor_name指定したカーソルに関連付けられている FETCH文によって処理された 後の行を参照します。カーソルは、FOR UPDATEであること、さらにオープンされていて行に置かれていることが必要です。

カーソルがオープンされていないと、CURRENT OF句でエラーが発生します。カーソルがオープンされていても、フェッチされた行がないか、 後のフェッチで行が戻されなかった場合は、PL/SQL によって事前定義の例外 NO_DATA_FOUNDが呼び出されます。

WHERE search_conditionデータベース表の中の更新対象行を選択します。検索条件を満たす行のみが更新されます。この句を省略すると、表の中のすべての行が更新されます。

PL/SQL の言語要素 13-187

Page 596: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

使用上の注意使用上の注意使用上の注意使用上の注意

UPDATE WHERE CURRENT OF文は、オープンされているカーソルからのフェッチ(カーソルFORループで実行されるフェッチを含む)の後で使用できます。ただしそのためには、関連付けられた問合せが FOR UPDATEである必要があります。この文は直前にフェッチされた行を更新します。

暗黙的な SQLカーソルとカーソル属性 %NOTFOUND、%FOUND、%ROWCOUNTおよび%ISOPENを使用すると、UPDATE文の実行に関する有用な情報にアクセスできます。

例例例例

次の例では、条件に基づいて表の行を更新する方法と、更新された値、列または行全体をPL/SQL 変数に格納する方法を示します。

-- Create some rows with values in all caps like (EMPLOYEES,TABLE)-- and (EMP_JOB_IX,INDEX).CREATE TABLE my_objects AS SELECT object_name, object_type FROM user_objects;

DECLARE my_name my_objects.object_name%TYPE; my_type my_objects.object_type%TYPE; TYPE name_typ IS TABLE OF my_objects.object_name%TYPE INDEX BY PLS_INTEGER; TYPE type_typ IS TABLE OF my_objects.object_type%TYPE INDEX BY PLS_INTEGER; all_names name_typ; all_types type_typ; TYPE table_typ IS TABLE OF my_objects%ROWTYPE INDEX BY PLS_INTEGER; all_rows table_typ;BEGIN-- Show the first 10 rows as they originally were. FOR obj IN (SELECT * FROM my_objects WHERE ROWNUM < 11) LOOP dbms_output.put_line('Name = ' || obj.object_name || ', type = ' || obj.object_type); END LOOP; UPDATE my_objects SET object_name = LOWER(object_name) WHERE object_type = 'TABLE'; dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows. ***');-- Show the first 10 rows after the update.-- Only some of the names (the table names) have been changed to lowercase. FOR obj IN (SELECT * FROM my_objects WHERE ROWNUM < 11) LOOP dbms_output.put_line('Name = ' || obj.object_name || ', type = ' || obj.object_type); END LOOP;

-- Update a single row, and store the values of updated (or unchanged)-- columns in variables.

13-188 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 597: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

UPDATE my_objects SET object_name = INITCAP(object_name) WHERE object_name = 'employees' RETURNING object_name, object_type INTO my_name, my_type;

dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows. ***'); dbms_output.put_line('Affected this row: ' || my_name || ', ' || my_type);

-- Update many rows, storing the values of updated (or unchanged)-- columns in collections of records. Can't use 'RETURNING *', have-- to list the columns individually. UPDATE my_objects SET object_name = INITCAP(object_name) WHERE object_type IN ('TRIGGER','VIEW','SEQUENCE') RETURNING object_name, object_type BULK COLLECT INTO all_rows;

dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows. ***'); FOR i IN all_rows.FIRST .. all_rows.LAST LOOP dbms_output.put_line('Affected this row: ' || all_rows(i).object_name || ', ' || all_rows(i).object_type); END LOOP;

-- Update many rows, storing the values of updated (or unchanged)-- columns in separate collections. (Generally less useful than using-- collections of records as above.) UPDATE my_objects SET object_name = INITCAP(object_name) WHERE object_type IN ('INDEX','PROCEDURE') RETURNING object_name, object_type BULK COLLECT INTO all_names, all_types;

dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows. ***'); FOR i IN all_names.FIRST .. all_names.LAST LOOP dbms_output.put_line('Affected this row: ' || all_names(i) || ', ' || all_types(i)); END LOOP;

END;/

DROP TABLE my_objects;

関連項目関連項目関連項目関連項目

DELETE 文、FETCH 文、INSERT 文

PL/SQL の言語要素 13-189

Page 598: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

UPDATE 文

13-190 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 599: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のサンプル・プログ

A

PL/SQL のサンプル・プログラムのサンプル・プログラムのサンプル・プログラムのサンプル・プログラム

この付録では、学習およびテスト用の PL/SQL サンプル・プログラムのコレクションが格納されている場所について説明します。

ラム A-1

Page 600: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のサンプル・プログラムの格納場所

PL/SQL のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所のサンプル・プログラムの格納場所サンプル・プログラムは、PL/SQL のデモ・ディレクトリにあります。デモ・ディレクトリの場所については、使用しているシステム用の Oracle のインストレーション・ガイドを参照してください。一般に、これらのサンプルは、表 EMPおよび表 DEPTを含む SCOTTスキーマに基づく古いプログラムです。

このマニュアルに掲載されたほとんどの例は、表 EMPLOYEESおよび表 DEPARTMENTSを含む HRサンプル・スキーマで実行できる、完全なプログラムとして構成されています。

Oracle Technology Network Japan の Web サイトの PL/SQL セクション(http://otn.oracle.co.jp/tech/pl_sql/)では、多くのサンプル・プログラムをダウンロードできます。これらのプログラムでは、多くの言語機能、特に 新の言語機能のデモを行います。一部のプログラムを使用して、データベースの複数のリリース間で PL/SQLのパフォーマンスを比較することもできます。

他の言語から PL/SQL をコールする例については、『Oracle Database Java 開発者ガイド』および『Pro*C/C++ Precompiler プログラマーズ・ガイド』を参照してください。

学習のガイドライン学習のガイドライン学習のガイドライン学習のガイドライン次に、知っておくと便利な PL/SQL プログラム構造体を示します。このマニュアルおよびWeb サイトのサンプル・プログラムから学習した後に、これらの各構造体の記述方法を理解していることを確認してください。

� 無名 PL/SQL ブロック。

� PL/SQL ストアド・プロシージャ。

� ストアド・プロシージャを起動する SQL の CALL文。ストアド・プロシージャを起動する無名ブロック。

� PL/SQL ストアド・ファンクション。

� ストアド・ファンクションをコールする SQL 問合せ。

� PL/SQL パッケージ。

� パッケージ・プロシージャをコールする無名ブロックまたはストアド・プロシージャ。パッケージ・ファンクションをコールする SQL 問合せ。

� マスター・スクリプトからコールされ、プロシージャ、ファンクションおよびパッケージのセットを作成する 1 つまたは一連の SQL*Plus スクリプト。

� 複数の INSERT、UPDATEまたは DELETE文を発行する(通常のループのかわりの)FORALL文。

A-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 601: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL における CHAR と VARCHAR2 の

B

PL/SQL におけるにおけるにおけるにおける CHAR とととと VARCHAR2 の意味の意味の意味の意味

この付録では、ベース型 CHARと VARCHAR2の意味上の相違点について説明します。わずかではありますが、重要なこれらの相違点は、文字値の代入、比較、挿入、更新、選択またはフェッチに影響を及ぼします。

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

� 文字値の代入(B-2 ページ)

� 文字値の比較(B-2 ページ)

� 文字値の挿入(B-3 ページ)

� 文字値の選択(B-4 ページ)

意味 B-1

Page 602: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

文字値の代入

文字値の代入文字値の代入文字値の代入文字値の代入文字値を CHAR型変数に割り当てるとき、変数の宣言された長さよりも値が短い場合、PL/SQL は、その値が宣言された長さと同じ長さになるまで空白を埋めます。元の値の後続する空白に関する情報は失われます。たとえば、次の宣言では、last_nameに割り当てられた値の後には、1 つではなく 6 つの空白ができます。

last_name CHAR(10) := 'CHEN '; -- note trailing blank

CHAR型変数の宣言された長さよりも文字値が長い場合、PL/SQL は代入を中止して事前定義済の例外 VALUE_ERRORを呼び出します。PL/SQL が値を切り捨てたり、後続する空白を切り捨てることはありません。たとえば、次のような宣言があるとします。

acronym CHAR(4);

次のような代入を試みると VALUE_ERRORが呼び出されます。

acronym := 'SPCA'; -- note trailing blank

文字値を VARCHAR2型変数に割り当てるとき、変数の宣言された長さよりも値が短い場合に、値を空白で埋めたり、値に後続する空白を削除することはありません。文字値はそのまま割り当てられ、情報は失われません。VARCHAR2型変数の宣言された長さよりも文字値が長い場合、PL/SQL は代入を中止して VALUE_ERRORを呼び出します。PL/SQL が値を切り捨てたり、後続する空白を切り捨てることはありません。

文字値の比較文字値の比較文字値の比較文字値の比較関係演算子を使用すると、2 つの文字値が等しいかどうかを比較できます。比較はデータベース・キャラクタ・セットの照合順番に基づいて行われます。文字値の比較では、照合順番で後の文字値が大きくなります。たとえば、次のような宣言があるとします。

last_name1 VARCHAR2(10) := 'COLES';last_name2 VARCHAR2(10) := 'COLEMAN';

次の IF 条件は TRUE です。

IF last_name1 > last_name2 THEN ...

SQL 標準では、比較する 2 つの文字値は同じ長さである必要があります。比較対象の値がいずれも CHARデータ型の場合、空白埋め比較方法が使用されます。つまり、長さが異なる文字値を比較する前に、短い方の値に、長い方の値と同じ長さになるまで空白が埋められます。たとえば、次のような宣言があるとします。

last_name1 CHAR(5) := 'BELLO';last_name2 CHAR(10) := 'BELLO '; -- note trailing blanks

B-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 603: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

文字値の挿入

次の IF条件は TRUE です。

IF last_name1 = last_name2 THEN ...

比較対象の値の一方が VARCHAR2データ型の場合、非空白埋め方法が使用されます。つまり、長さが異なる文字値を比較する場合に、PL/SQL によって調整は行われず、そのままの長さが使用されます。たとえば、次のような宣言があるとします。

last_name1 VARCHAR2(10) := 'DOW';last_name2 VARCHAR2(10) := 'DOW '; -- note trailing blanks

次の IF条件は FALSE です。

IF last_name1 = last_name2 THEN ...

VARCHAR2の値と CHARの値が比較される場合、非空白埋め比較方法が使用されます。ただし、文字値を CHAR変数に割り当てるときに、その値が変数の宣言された長さよりも短い場合、PL/SQL は、その値が宣言された長さになるまで空白を埋めます。たとえば、次のような宣言があるとします。

last_name1 VARCHAR2(10) := 'STAUB';last_name2 CHAR(10) := 'STAUB'; -- PL/SQL blank-pads value

last_name2の値の後に 5 つの空白が含まれるため、次の IF条件は FALSE です。

IF last_name1 = last_name2 THEN ...

すべての文字列リテラルは、CHARデータ型を持っています。比較対象の値の両方がリテラルの場合は、空白埋め比較方法が使用されます。片方の値がリテラルの場合は、残りの値がCHARデータ型の場合にのみ、空白埋め比較方法が使用されます。

文字値の挿入文字値の挿入文字値の挿入文字値の挿入PL/SQL 文字変数の値を Oracle データベース列に挿入する場合、それが空白埋めされるかどうかは、変数の型ではなく列の型に依存します。

文字値を CHARデータベース列に挿入する場合、Oracle は値に後続する空白を削除しません。列の定義された幅よりも値が短ければ、Oracle は、定義された幅まで値を空白で埋めます。その結果、後続する空白に関する情報は失われます。定義されている列幅よりも文字値が長い場合、Oracle は挿入を中止してエラーを生成します。

文字値を VARCHAR2データベース列に挿入する場合、Oracle は値に後続する空白を削除しません。列の定義された幅よりも値が短い場合も、Oracle は値の空白埋めをしません。文字値はそのまま格納されるため、情報は失われません。定義されている列幅よりも文字値が長い場合、Oracle は挿入を中止してエラーを生成します。

注意注意注意注意 : 更新の場合にも同じ規則が適用されます。

PL/SQL における CHAR と VARCHAR2 の意味 B-3

Page 604: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

文字値の選択

文字値を挿入するとき、RTRIMファンクションを使用することによって、後続する空白が切り捨てられ、後続する空白を格納しないようにできます。次に例を示します。

DECLARE ... my_name VARCHAR2(15);BEGIN ... my_ename := 'LEE '; -- note trailing blanks INSERT INTO emp VALUES (my_empno, RTRIM(my_ename), ...); -- inserts 'LEE'END;

文字値の選択文字値の選択文字値の選択文字値の選択Oracle データベース列から値を選択して PL/SQL 文字変数に入れる場合、それが空白埋めされるかどうかは、列の型ではなく変数の型に依存します。

列値を選択して CHAR変数に入れる場合、変数の宣言された長さよりも値が短ければ、PL/SQL は宣言された長さまで値を空白で埋めます。その結果、後続する空白に関する情報は失われます。文字値が変数の宣言された長さより長い場合、PL/SQL は代入を中止して例外 VALUE_ERRORを呼び出します。

列値を選択して VARCHAR2変数に入れる場合、その値が変数の宣言された長さよりも短いと、PL/SQL は空白埋めも、後続する空白の削除もしません。文字値はそのまま格納されるため、情報は失われません。

たとえば、空白で埋められた CHAR列値を選択して VARCHAR2変数に入れる場合、後続する空白は削除されません。VARCHAR2型変数の宣言された長さよりも文字値が長い場合、PL/SQL は代入を中止して VALUE_ERRORを呼び出します。

注意注意注意注意 : フェッチの場合にも同じ規則が適用されます。

B-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 605: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ラップ・ユーティリティを使用したソース・コードの不明

C

PL/SQL ラップ・ユーティリティを使用したラップ・ユーティリティを使用したラップ・ユーティリティを使用したラップ・ユーティリティを使用した

ソース・コードの不明瞭化ソース・コードの不明瞭化ソース・コードの不明瞭化ソース・コードの不明瞭化

この付録では、ラップ・ユーティリティを実行する方法を示します。ラップ・ユーティリティは、PL/SQL ソース・コードを不明瞭化し、ソース・コードを隠したまま PL/SQL アプリケーションを配布できるようにするスタンドアロン・プログラムです。

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

� PL/SQL プロシージャのラッピングのメリット(C-2 ページ)

� PL/SQL ラップ・ユーティリティの実行(C-2 ページ)

� PL/SQL ラップ・ユーティリティの制限(C-4 ページ)

瞭化 C-1

Page 606: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL プロシージャのラッピングのメリット

PL/SQL プロシージャのラッピングのメリットプロシージャのラッピングのメリットプロシージャのラッピングのメリットプロシージャのラッピングのメリット� ラップ・ユーティリティは、アプリケーション内部を隠すことによって、他の開発者に

よるアプリケーションの間違った使用や、アルゴリズムの競合他社への公開を防ぐことを目的としています。

� コードは、USER_SOURCE、ALL_SOURCEまたは DBA_SOURCEデータ・ディクショナリ・ビューから参照できません。

� ラップされたファイルを SQL*Plus で処理できます。PL/SQL プロシージャおよびパッケージを作成するソース・ファイルを不明瞭化できます。

� インポート / エクスポート・ユーティリティで、ラップされたファイルを扱えます。ラップされたプロシージャのバックアップまたは移動を実行できます。

PL/SQL ラップ・ユーティリティの実行ラップ・ユーティリティの実行ラップ・ユーティリティの実行ラップ・ユーティリティの実行ラップ・ユーティリティを実行するには、次の構文を使用して、オペレーティング・システム・プロンプトで wrapコマンドを入力します。

wrap iname=input_file [oname=output_file]

注意注意注意注意 : 等号の前後には空白を使用しないでください。

input_fileは、通常、SQL*Plus を使用して実行する、SQL 文を含むファイルの名前です。ファイル拡張子を省略すると、拡張子は .sqlであるとみなされます。たとえば、次のコマンドは同じ意味を持ちます。

wrap iname=/mydir/myfilewrap iname=/mydir/myfile.sql

次のように、異なるファイル拡張子を指定することもできます。

wrap iname=/mydir/myfile.src

output_fileは、作成するファイル(不明瞭化されたファイル)の名前です。onameは任意に指定します。出力ファイル名はデフォルトで入力ファイルの名前となり、拡張子はデフォルトで .plbとなります。たとえば、次のコマンドは同じ意味を持ちます。

wrap iname=/mydir/myfilewrap iname=/mydir/myfile.sql oname=/mydir/myfile.plb

次に示すように、onameオプションを使用して、異なるファイル名と拡張子を指定できます。

wrap iname=/mydir/myfile oname=/yourdir/yourfile.out

C-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 607: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ラップ・ユーティリティの実行

PL/SQL ラップ・ユーティリティの入力ファイルと出力ファイルラップ・ユーティリティの入力ファイルと出力ファイルラップ・ユーティリティの入力ファイルと出力ファイルラップ・ユーティリティの入力ファイルと出力ファイル入力ファイルでは、SQL 文を任意に組み合せることができます。ほとんどの文はそのままの形で渡されます。サブプログラム、パッケージまたはオブジェクト型を定義する CREATE文は、不明瞭化されます。これらの文の本体は、隠ぺいされた(ただし PL/SQL コンパイラが理解可能な)形式に置き換えられます。

次の CREATE 文は不明瞭化されます。

CREATE [OR REPLACE] FUNCTION function_nameCREATE [OR REPLACE] PROCEDURE procedure_nameCREATE [OR REPLACE] PACKAGE package_nameCREATE [OR REPLACE] PACKAGE BODY package_nameCREATE [OR REPLACE] TYPE type_name AS OBJECTCREATE [OR REPLACE] TYPE type_name UNDER type_nameCREATE [OR REPLACE] TYPE BODY type_name

注意注意注意注意 : CREATE [OR REPLACE] TRIGGER文および BEGIN..END無名ブロックは不明瞭化されません。

その他の SQL 文はすべて、そのままの形で出力ファイルに渡されます。ほとんどのコメント行は削除されます。C 形式のコメント(/* */で区切られる)は、SQL 文中で使用されている場合は保持されます。また、CREATE文の直後で不明瞭化される本体の前に記述されているコメントも保持されます。

出力ファイルはテキスト・ファイルです。このファイルを SQL*Plus で次のように実行し、PL/SQL プロシージャ、ファンクションおよびパッケージを設定できます。

SQL> @wrapped_file_name.plb;

ヒントヒントヒントヒント :

� パッケージまたはオブジェクト型をラップする場合は、仕様部ではなく、本体のみをラップします。こうすると、他の開発者は、パッケージまたは型を使用するのに必要な情報を見ることができますが、その実装は見えません。

� ラップされたファイル内の PL/SQL ソースは編集できません。ラップされた PL/SQLコードを変更するには、元のソース・ファイルを編集し、再度ラップします。エンド・ユーザーに出荷する用意ができるまでコードをラップしないようにするか、または構築環境でラッピング操作を行うことができます。

� ソース・コードのすべての重要な部分が不明瞭化されていることを確認するために、配布前に、ラップされたファイルをテキスト・エディタで表示してください。

PL/SQL ラップ・ユーティリティを使用したソース・コードの不明瞭化 C-3

Page 608: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL ラップ・ユーティリティの制限

PL/SQL ラップ・ユーティリティの制限ラップ・ユーティリティの制限ラップ・ユーティリティの制限ラップ・ユーティリティの制限� コンパイル・ユニットをラップすると、アルゴリズムが隠ぺいされ、リバース・エンジ

ニアリングの防止に役立ちますが、パスワードまたは表名を隠ぺいするための保護方法としてこの方法を使用しないことをお薦めします。

� ソース・コードは SQL*Plus ではなく PL/SQL コンパイラで解析されるため、PL/SQLコードに SQL*Plus の DEFINE表記法を使用して置換変数を含めることはできません。他の不明瞭化しない SQL 文では、置換変数を使用できます。

� ラップ・ユーティリティでは、トリガー用のソース・コードは不明瞭化されません。ラップされたプロシージャをコールする 1 行トリガーを記述すると、トリガーの動作を隠すことができます。

� 一部のコメントは、ラップされたファイルで削除されます。

� PL/SQL コンパイル・ユニットに構文エラーが含まれている場合、ラップ・ユーティリティはそのエラーを検出し、レポートします。ラップ・ユーティリティは、表またはビューが存在しないなどのセマンティック・エラーは検出しません。これらのエラーは、SQL*Plus で出力ファイルを実行したときに検出されます。

� ラップ・ユーティリティは、Oracle の複数のリリース間で上位互換性を持ちますが、下位互換性は持ちません。たとえば、リリース 8.1.5 のラップ・ユーティリティで処理されたファイルは、リリース 8.1.6 の Oracle データベースにロードできますが、リリース8.1.6 のラップ・ユーティリティで処理されたファイルは、リリース 8.1.5 の Oracle データベースにロードできません。

C-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 609: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL での識別子名の

D

PL/SQL での識別子名の解決での識別子名の解決での識別子名の解決での識別子名の解決

この付録では、潜在的に意味の曖昧なプロシージャ文および SQL 文で、名前への参照をPL/SQL がどのように解決するかについて説明します。

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

� 名前解決(D-2 ページ)

� 修飾名およびドット表記法の例(D-3 ページ)

� SQL と PL/SQL の名前解決の相違点(D-4 ページ)

� 取得の理解(D-4 ページ)

� DML 文の内部取得の回避(D-6 ページ)

� オブジェクト属性およびメソッドへの参照の修飾(D-6 ページ)

� パラメータを持たないサブプログラムとメソッドのコール(D-7 ページ)

� SQL と PL/SQL の名前解決の比較(D-8 ページ)

解決 D-1

Page 610: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

名前解決

名前解決名前解決名前解決名前解決コンパイルの際に、PL/SQL コンパイラは、PL/SQL サブプログラムの各名前と関連付けるオブジェクトを判別します。名前は、ローカル変数、表、パッケージ、プロシージャ、スキーマなどを参照する場合があります。オブジェクトが作成または削除されている場合、サブプログラムが再コンパイルされると、その関連付けが変更されることがあります。

内部有効範囲における宣言または定義で、外部有効範囲における別の宣言または定義が隠される可能性があります。PL/SQL の名前では大 / 小文字が区別されないため、次の例では、client変数の宣言によって Clientデータ型の定義が隠されています。

BEGIN <<block1>> DECLARE TYPE Client IS RECORD (...); TYPE Customer IS RECORD (...); BEGIN DECLARE client Customer; -- hides definition of type Client -- in outer scope lead1 Client; -- not allowed; Client resolves to the -- variable client lead2 block1.Client; -- OK; refers to type Client BEGIN NULL; END; END; END;

ただし、この場合でも、ブロック・ラベル block1で参照を修飾することで、Clientデータ型を参照できます。

次の CREATE TYPE文では、2 つ目の文によってエラーが生成されます。MANAGERという名前の属性を作成すると、MANAGERという名前の型が隠されるため、2 つ目の属性の宣言は無効です。

CREATE TYPE manager AS OBJECT (dept NUMBER);/CREATE TYPE person AS OBJECT (manager NUMBER, mgr manager);/

D-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 611: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

修飾名およびドット表記法の例

修飾名およびドット表記法の例修飾名およびドット表記法の例修飾名およびドット表記法の例修飾名およびドット表記法の例名前解決の際、コンパイラは、単なる未修飾の名前、ドットで区切られて連鎖した識別子、コレクションの索引付きのコンポーネントなど、様々な種類の参照に遭遇する可能性があります。次に例を示します。

CREATE PACKAGE pkg1 AS m NUMBER; TYPE t1 IS RECORD (a NUMBER); v1 t1; TYPE t2 IS TABLE OF t1 INDEX BY BINARY_INTEGER; v2 t2; FUNCTION f1 (p1 NUMBER) RETURN t1; FUNCTION f2 (q1 NUMBER) RETURN t2;END pkg1;

CREATE PACKAGE BODY pkg1 AS FUNCTION f1 (p1 NUMBER) RETURN t1 IS n NUMBER; BEGIN n := m; -- (1) unqualified name n := pkg1.m; -- (2) dot-separated chain of identifiers -- (package name used as scope -- qualifier followed by variable name) n := pkg1.f1.p1; -- (3) dot-separated chain of identifiers -- (package name used as scope -- qualifier followed by function name -- also used as scope qualifier -- followed by parameter name) n := v1.a; -- (4) dot-separated chain of identifiers -- (variable name followed by -- component selector) n := pkg1.v1.a; -- (5) dot-separated chain of identifiers -- (package name used as scope -- qualifier followed by -- variable name followed by component -- selector) n := v2(10).a; -- (6) indexed name followed by component -- selector n := f1(10).a; -- (7) function call followed by component -- selector n := f2(10)(10).a; -- (8) function call followed by indexing -- followed by component selector n := scott.pkg1.f2(10)(10).a; -- (9) function call (which is a dot- -- separated chain of identifiers, -- including schema name used as

PL/SQL での識別子名の解決 D-3

Page 612: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL と PL/SQL の名前解決の相違点

-- scope qualifier followed by package -- name used as scope qualifier -- followed by function name) -- followed by component selector -- of the returned result followed -- by indexing followed by component -- selector n := scott.pkg1.f1.n; -- (10) dot-separated chain of identifiers -- (schema name used as scope qualifier -- followed by package name also used -- as scope qualifier followed by -- function name also used as scope -- qualifier followed by local -- variable name) ... END f1;

FUNCTION f2 (q1 NUMBER) RETURN t2 IS BEGIN ... END f2; END pkg1;

SQL とととと PL/SQL の名前解決の相違点の名前解決の相違点の名前解決の相違点の名前解決の相違点PL/SQL コンパイラが DML 文などの SQL 文を処理する場合、SQL と同じ名前解決の規則が使用されます。たとえば、SCOTT.FOOという名前の場合、SQL では、まず SCOTTスキーマでオブジェクトが検索され、次に現行スキーマでパッケージ、型、表およびビューが検索されます。

PL/SQL では、代入やプロシージャのコールなどの PL/SQL 文の名前は、異なる順序で解決されます。SCOTT.FOOという名前の場合、PL/SQL では、まず現行スキーマで SCOTTという名前のパッケージ、型、表およびビューが検索され、次に SCOTTスキーマでオブジェクトが検索されます。

取得の理解取得の理解取得の理解取得の理解別の有効範囲における宣言または型の定義が参照の正常な解決の妨げになる場合、その宣言または定義が参照を「取得する」と呼びます。通常、これは移行またはスキーマのアップグレードの結果として生じます。取得には、内部、同一有効範囲および外部の 3 種類があります。内部および同一有効範囲の取得は SQL スコープにのみ適用されます。

D-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 613: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

取得の理解

内部取得内部取得内部取得内部取得内部取得が発生するのは、内部有効範囲に含まれる名前が外部有効範囲のエンティティを参照しておらず、次のような状態が発生した場合です。

� 内部有効範囲に含まれるエンティティに名前が解決される場合。

� 識別子の一部が内部有効範囲に取得され、参照を完全に解決することができず、プログラムでエラーが発生する場合。

参照が別の有効な名前を指す場合、プログラムが目的と異なる動作を行う理由を認識できない可能性があります。

次の例では、内側の SELECT文における col2への参照は、表 tab2が col2という名前の列を持たないため、表 tab1の列 col2にバインドされます。

CREATE TABLE tab1 (col1 NUMBER, col2 NUMBER);CREATE TABLE tab2 (col1 NUMBER);CREATE PROCEDURE proc AS CURSOR c1 IS SELECT * FROM tab1 WHERE EXISTS (SELECT * FROM tab2 WHERE col2 = 10);BEGIN ...END;

この例で、次に示すように、表 tab2に列 col2を追加した場合を考えます。

ALTER TABLE tab2 ADD (col2 NUMBER);

この場合には、プロシージャ procは無効となり、次に使用する際に、自動的に再コンパイルされます。ただし、再コンパイルの際に、tab2は内部有効範囲にあるため、内側のSELECT文の col2は tab2の列 col2にバインドされます。したがって、表 tab2への列col2の追加によって、col2への参照は取得されます。

コレクションやオブジェクト型を使用することによって、さらに多くの内部取得が発生する可能性があります。次の例では、s.tab2.aへの参照は、問合せの外部有効範囲で参照することのできる表の別名 sを経由して、表 tab1の列 tab2の属性 aに解決されます。

CREATE TYPE type1 AS OBJECT (a NUMBER);CREATE TABLE tab1 (tab2 type1);CREATE TABLE tab2 (x NUMBER);SELECT * FROM tab1 s -- alias with same name as schema name WHERE EXISTS (SELECT * FROM s.tab2 WHERE x = s.tab2.a); -- note lack of alias

PL/SQL での識別子名の解決 D-5

Page 614: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

DML 文の内部取得の回避

この例で、内側の副問合せに現れる表 s.tab2に列名 aを追加することを考えます。問合せが処理されると、s.tab2.aへの参照がスキーマ s内の表 tab2の列 aに解決されるため、内部取得が発生します。内部取得を防止するには、D-6 ページの「DML 文の内部取得の回避」で説明するルールに従います。これらのルールに従えば、この問合せは、次のように書き換わります。

SELECT * FROM s.tab1 p1 WHERE EXISTS (SELECT * FROM s.tab2 p2 WHERE p2.x = p1.tab2.a);

同一有効範囲の取得同一有効範囲の取得同一有効範囲の取得同一有効範囲の取得SQL スコープで、同一有効範囲の取得が発生するのは、結合に使用される 2 つの表のどちらかに列が追加され、どちらの表にも同じ列名が存在する場合です。結合問合せのその列名を事前に参照できます。エラーを回避するには、列名を表名で修飾する必要があります。

外部取得外部取得外部取得外部取得外部取得が発生するのは、過去に内部有効範囲内のエンティティに解決されていた内部有効範囲内の名前が、外部有効範囲に解決された場合です。SQL と PL/SQL は、外部取得を防止する設計になっています。この状態を回避するためのアクションは必要ありません。

DML 文の内部取得の回避文の内部取得の回避文の内部取得の回避文の内部取得の回避次のルールを遵守することによって、DML 文における内部取得を防止できます。

� DML 文内の各表に対して別名を指定します。

� DML 文の全体を通じて、表の別名を一意に保ちます。

� 問合せ内で使用されているスキーマ名と一致する表の別名の使用を避けます。

� 列の参照を表の別名で修飾します。

文がユーザー定義のオブジェクト型の列を持つ表を参照している場合には、schema_name.table_nameで参照を修飾しても内部取得は防止できません。

オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾オブジェクト属性およびメソッドへの参照の修飾ユーザー定義のオブジェクト型の列によって、より多くの内部取得が発生する可能性があります。問題を 小限に抑えるため、次のルールが名前解決アルゴリズムに含まれています。

� 属性およびメソッドへのすべての参照が、表の別名によって修飾されている必要があります。表を参照する場合、その表に格納されているオブジェクトの属性やメソッドを参照するときには、表名に別名を添付する必要があります。次の例に示すとおり、属性またはメソッドへの列修飾された参照は、その参照に接頭辞として表名が使用されている場合は使用できません。

D-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 615: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

パラメータを持たないサブプログラムとメソッドのコール

CREATE TYPE t1 AS OBJECT (x NUMBER); CREATE TABLE tb1 (col t1); SELECT col.x FROM tb1; -- not allowed SELECT tb1.col.x FROM tb1; -- not allowed SELECT scott.tb1.col.x FROM scott.tb1; -- not allowed SELECT t.col.x FROM tb1 t;UPDATE tb1 SET col.x = 10; -- not allowed UPDATE scott.tb1 SET scott.tb1.col.x=10; -- not allowed UPDATE tb1 t set t.col.x = 1;DELETE FROM tb1 WHERE tb1.col.x = 10; -- not allowed DELETE FROM tb1 t WHERE t.col.x = 10;

� 行の式は、表の別名への参照として解決する必要があります。行の式を REFおよびVALUEに渡したり、UPDATE文の SET句に行の式を使用できます。次に例を示します。

CREATE TYPE t1 AS OBJECT (x number);CREATE TABLE ot1 OF t1; -- object tableSELECT REF(ot1) FROM ot1; -- not allowedSELECT REF(o) FROM ot1 o; SELECT VALUE(ot1) FROM ot1; -- not allowedSELECT VALUE(o) FROM ot1 o; DELETE FROM ot1 WHERE VALUE(ot1) = (t1(10)); -- not allowedDELETE FROM ot1 o WHERE VALUE(o) = (t1(10));UPDATE ot1 SET ot1 = ... -- not allowedUPDATE ot1 o SET o = ....

オブジェクト表に挿入するための次に示す各方法は有効です。また、列のリストを持たないため、別名は必要とされません。

INSERT INTO ot1 VALUES (t1(10)); -- no row expressionINSERT INTO ot1 VALUES (10); -- no row expression

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

パラメータを取らないメソッドをコールする場合、PL/SQL スコープでは空のカッコはオプションですが、SQL スコープでは必須です。

PL/SQL での識別子名の解決 D-7

Page 616: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQL と PL/SQL の名前解決の比較

SQL とととと PL/SQL の名前解決の比較の名前解決の比較の名前解決の比較の名前解決の比較SQL と PL/SQL の名前解決ルールはよく似ています。取得回避規則に従っている場合は、いくつかの小さい違いは回避できます。

互換性のため、SQL ルールは PL/SQL と比較して、より許容性が高くなっています。つまり、そのほとんどが状況依存な SQL ルールでは、PL/SQL ルールで認識されるよりも多くの状況と DML 文が、有効なものと認識されます。

D-8 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 617: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のプログラム上の

E

PL/SQL のプログラム上の制限のプログラム上の制限のプログラム上の制限のプログラム上の制限

この付録では、PL/SQL 言語によって課されるプログラム上の制限について説明します。

PL/SQL はプログラミング言語 Ada をベースにしています。したがって PL/SQL では、ツリー構造の中間言語、DIANA(Descriptive Intermediate Attributed Notation for Ada)を使用しています。この中間言語は、インタフェース定義言語(IDL)と呼ばれるメタ表記を使用して定義されます。DIANA は、コンパイラなどのツールによって内部的に使用されます。

PL/SQL のソース・コードはコンパイル時に機械可読の m コードに変換されます。1 つのプロシージャまたはパッケージに対応する DIANA および m コードの両方がデータベースに格納されます。実行時に DIANA と m コードは共有メモリー・プール内にロードされます。DIANA は依存プロシージャのコンパイルに使用され、m コードはそのまま実行されます。

共有メモリー・プールの場合、パッケージ仕様部、オブジェクト型仕様部、スタンドアロン・サブプログラムまたは無名ブロックは、2**26 個の DIANA ノードに制限されています

(ノードは、識別子、キーワード、演算子などのトークンに対応します)。PL/SQL コンパイラによる制限を超えないかぎり、6,000,000 行以下のコードが許されます。PL/SQL コンパイラによる一部の制限を表 E-1 に示します。

表表表表 E-1 PL/SQL コンパイラの制限コンパイラの制限コンパイラの制限コンパイラの制限

項目項目項目項目 制限制限制限制限

プログラム・ユニットに渡されるバインド変数 32K

プログラム・ユニット内の例外ハンドラ 64K

レコード内のフィールド 64K

ブロック・ネストのレベル 255

レコード・ネストのレベル 32

副問合せネストのレベル 254

ラベル・ネストのレベル 98

BINARY_INTEGER値の絶対値 2G

制限 E-1

Page 618: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PLS_INTEGER値の絶対値 2G

プログラム・ユニットから参照されるオブジェクト 64K

明示カーソルに渡されるパラメータ 64K

ファンクションまたはプロシージャに渡されるパラメータ

64K

FLOAT値(2 進数)の精度 126

NUMBER値(10 進数)の精度 38

REAL値(2 進数)の精度 63

識別子のサイズ(文字) 30

文字列リテラルのサイズ(バイト) 32K

CHAR値(バイト)のサイズ 32K

LONG値(バイト)のサイズ 32K-7

LONG RAW値(バイト)のサイズ 32K-7

RAW値(バイト)のサイズ 32K

VARCHAR2値(バイト)のサイズ 32K

NCHAR値(バイト)のサイズ 32K

NVARCHAR2値(バイト)のサイズ 32K

BFILE値(バイト)のサイズ 4G × DB_BLOCK_SIZE パラメー

タの値

BLOB値(バイト)のサイズ 4G × DB_BLOCK_SIZE パラメー

タの値

CLOB値(バイト)のサイズ 4G × DB_BLOCK_SIZE パラメー

タの値

NCLOB値(バイト)のサイズ 4G × DB_BLOCK_SIZE パラメー

タの値

表表表表 E-1 PL/SQL コンパイラの制限コンパイラの制限コンパイラの制限コンパイラの制限(続き)(続き)(続き)(続き)

項目項目項目項目 制限制限制限制限

E-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 619: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プログラム・ユニットに必要なメモリー量を見積もるときには、データ・ディクショナリ・ビュー user_object_sizeを使用して問い合せることができます。parsed_sizeという列に、フラット化された DIANA のバイト・サイズが戻ります。次に例を示します。

SQL> SELECT * FROM user_object_size WHERE name = 'PKG1';

NAME TYPE SOURCE_SIZE PARSED_SIZE CODE_SIZE ERROR_SIZE--------------------------------------------------------------------PKG1 PACKAGE 46 165 119 0PKG1 PACKAGE BODY 82 0 139 0

ただし、サイズの解析結果から DIANA ノードの数を見積もることはできません。解析後のサイズが同じプログラム・ユニットが 2 つあり、一方に必要な DIANA ノードの数が 1500に対して、他方に必要なのが 2000 である(2 番目のユニットに含まれる SQL 文が複雑であるなどの理由で)場合もあるためです。

PL/SQL ブロック、サブプログラム、パッケージまたはオブジェクト型のいずれかがサイズの限度を超えると、「プログラムが大きすぎます。」などのエラーとなります。多くの場合、この問題はパッケージまたは無名ブロックで発生します。パッケージの場合、 良の方法は複数個のより小さなパッケージに分けることです。無名ブロックの場合、 良の方法はサブプログラムのグループとして再定義し、データベースに格納できるようにすることです。

PL/SQL のプログラム上の制限 E-3

Page 620: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

E-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 621: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL の予約語のリ

F

PL/SQL の予約語のリストの予約語のリストの予約語のリストの予約語のリスト

この付録では、PL/SQL で使用するために予約されている予約語のリストを示します。定数、変数、カーソルなどのプログラム・オブジェクトの名前には使用しないでください。これらの単語の中で、アスタリスクの付いたものは SQL の予約語でもあります。列、表、索引などのスキーマ・オブジェクトの名前には使用しないでください。

スト F-1

Page 622: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ALL*ALTER*AND*ANY*ARRAYAS*ASC*ATAUTHIDAVGBEGINBETWEEN*BINARY_INTEGERBODYBOOLEANBULKBY*CASECHAR*CHAR_BASECHECK*CLOSECLUSTER*COALESCECOLLECTCOMMENT*COMMITCOMPRESS*CONNECT*CONSTANTCREATE*CURRENT*CURRVALCURSORDATE*DAYDECLAREDECIMAL*DEFAULT*DELETE*DESC*DISTINCT*DODROP*ELSE*ELSIFENDEXCEPTIONEXCLUSIVE*

EXECUTEEXISTS*EXITEXTENDSEXTRACTFALSEFETCHFLOAT*FOR*FORALLFROM*FUNCTIONGOTOGROUP*HAVING*HEAPHOURIFIMMEDIATE*IN*INDEX*INDICATORINSERT*INTEGER*INTERFACEINTERSECT*INTERVALINTO*IS*ISOLATIONJAVALEVEL*LIKE*LIMITEDLOCK*LONG*LOOPMAXMINMINUS*MINUTEMLSLABEL*MODMODE*MONTHNATURALNATURALNNEWNEXTVAL

NOCOPYNOT*NOWAIT*NULL*NULLIFNUMBER*NUMBER_BASEOCIROWIDOF*ON*OPAQUEOPENOPERATOROPTION*OR*ORDER*ORGANIZATIONOTHERSOUTPACKAGEPARTITIONPCTFREE*PLS_INTEGERPOSITIVEPOSITIVENPRAGMAPRIOR*PRIVATEPROCEDUREPUBLIC*RAISERANGERAW*REALRECORDREFRELEASERETURNREVERSEROLLBACKROW*ROWID*ROWNUM*ROWTYPESAVEPOINTSECONDSELECT*SEPARATESET*

SHARE*SMALLINT*SPACESQLSQLCODESQLERRMSTART*STDDEVSUBTYPESUCCESSFUL*SUMSYNONYM*SYSDATE*TABLE*THEN*TIMETIMESTAMPTIMEZONE_REGIONTIMEZONE_ABBRTIMEZONE_MINUTETIMEZONE_HOURTO*TRIGGER*TRUETYPEUID*UNION*UNIQUE*UPDATE*USEUSER*VALIDATE*VALUES*VARCHAR*VARCHAR2*VARIANCEVIEW*WHENWHENEVER*WHERE*WHILEWITH*WORKWRITEYEARZONE

F-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 623: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL に関する

G

PL/SQL に関するに関するに関するに関する FAQ

この付録では、PL/SQL に関するよくある質問とその回答の一部を示します。必要に応じて、回答には詳細情報の参照先を示します。

PL/SQL に関するよくある質問と回答は、Web サイト http://asktom.oracle.com/でも参照できます。PL/SQL の詳細な動作を示した例については、Oracle Technology Network Japan の Web サイトの「PL/SQL」ページ

(http://otn.oracle.co.jp/tech/pl_sql/)を参照してください。

FAQ G-1

Page 624: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL でのバインド変数の使用

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

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

動的動的動的動的 SQL でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略でのセミコロンの使用または省略単一の SQL 文を 1 つの文字列として記述する場合、文末(引用符の内側)にセミコロンを置かないでください。

無名 PL/SQL ブロックを記述する場合、各 PL/SQL 文の文末および無名ブロックの 後にセミコロンを置きます。文字列リテラルの終了一重引用符の直前と直後にセミコロンを置くことになります。

PL/SQL での正規表現の使用での正規表現の使用での正規表現の使用での正規表現の使用正規表現による検索には、SQL 演算子 REGEXP_LIKEを使用します。

文字列のテストまたは操作には、組込みファンクション REGEXP_INSTR、REGEXP_REPLACEおよび REGEXP_SUBSTRを使用します。

Oracle の正規表現機能では、UNIX や Perl プログラミングでも使用される「.」、「*」、「^」、「$」などの文字を使用します。多言語用のプログラミングの場合、その他の拡張機能も使用できます。たとえば、小文字の検索で、アクセント記号付きの小文字には一致しない [a-z]のかわりに、[:lower:] を使用できます。

G-2 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 625: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL のドット表記法を使用した様々な要素名の指定

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

PL/SQL でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型でのユーザー定義型または抽象データ型PL/SQL では、これらの型を「オブジェクト型」といいます。オブジェクト指向プログラミングを行うには、SQL と PL/SQL を併用します。型自体およびそれらの型を保持する表の作成には、SQL を使用します。メソッドの本体の作成、およびオブジェクトの表の操作とオブジェクトのメソッドのコールには、PL/SQL を使用します。

PL/SQL を使用したオブジェクト指向プログラミングの詳細は、『Oracle Database アプリケーション開発者ガイド - オブジェクト・リレーショナル機能』を参照してください。

PL/SQL からからからから Java またはまたはまたはまたは Visual Basic((((VB)への結果セットの引)への結果セットの引)への結果セットの引)への結果セットの引渡し渡し渡し渡し

PL/SQL では、REF CURSORというカーソル変数を使用して、問合せを発行して結果セットを戻すことができます。6-25 ページの「カーソル変数(REF CURSOR)の使用」を参照してください。

PL/SQL のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定のドット表記法を使用した様々な要素名の指定ドット表記法は、レコード・フィールド、オブジェクト属性、およびパッケージや他のスキーマ内の要素を識別するために使用します。これらの要素を組み合せる際、複数レベルのドットを含む式を使用する必要がある場合がありますが、その場合は各ドットが示すものがわかりにくくなることもあります。組合せの例を次に示します。

ファンクションの戻り値のフィールドまたは属性ファンクションの戻り値のフィールドまたは属性ファンクションの戻り値のフィールドまたは属性ファンクションの戻り値のフィールドまたは属性func_name().field_namefunc_name().attribute_name

別のスキーマが所有するスキーマ・オブジェクト別のスキーマが所有するスキーマ・オブジェクト別のスキーマが所有するスキーマ・オブジェクト別のスキーマが所有するスキーマ・オブジェクトschema_name.table_nameschema_name.procedure_name()schema_name.type_name.member_name()

PL/SQL に関する FAQ G-3

Page 626: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

PL/SQL でのオブジェクトおよびオブジェクト型の使用

別のユーザーが所有するパッケージ・オブジェクト別のユーザーが所有するパッケージ・オブジェクト別のユーザーが所有するパッケージ・オブジェクト別のユーザーが所有するパッケージ・オブジェクトschema_name.package_name.procedure_name()schema_name.package_name.record_name.field_name

オブジェクト型を含むレコードオブジェクト型を含むレコードオブジェクト型を含むレコードオブジェクト型を含むレコードrecord_name.field_name.attribute_namerecord_name.field_name.member_name()

PL/SQL でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用でのオブジェクトおよびオブジェクト型の使用オブジェクト型を作成するには、動的 SQL(EXECUTE IMMEDIATE文)を使用して SQL のCREATE TYPE文を発行します。

オブジェクトを使用すると、レコードのグループ化と同様に、関連する値をグループ化できます。オブジェクトは直接データベースに格納できるというメリットがあります。また、オブジェクトの VARRAY、ネストした表および結合配列も作成できます。

オブジェクトをパラメータとして受け入れる PL/SQL プロシージャおよびファンクションを作成できます。これらのプロシージャおよびファンクションには、オブジェクトをパラメータとして渡すことができます。ファンクションからオブジェクトを戻すこともできます。

PL/SQL のオブジェクト型用のメンバー・プロシージャおよびファンクションを作成できます。

同じスーパータイプの異なるサブタイプをパラメータとして受け入れる PL/SQL プロシージャおよびファンクションを定義して、オーバーロードされた PL/SQL プロシージャおよびファンクションを作成できます。

完全にオブジェクト指向に基づいた PL/SQL アプリケーションを記述できます。

オブジェクトおよびオブジェクト型を使用して PL/SQL の変数およびパラメータの制限事項を回避し、大部分が手続き型に基づいた PL/SQL アプリケーションを記述できます。

PL/SQL プロシージャの作成プロシージャの作成プロシージャの作成プロシージャの作成次に示す様々な方法で、様々な PL/SQL プロシージャおよびファンクションを作成できます。

SQL の CREATE PROCEDUREおよび CREATE FUNCTION文を使用します。

SQL の CREATE TRIGGER文を使用します。

SQL の CREATE PACKAGEおよび CREATE PACKAGE BODY文を使用します。パッケージ本体には、プロシージャとファンクションの両方を含めることができます。

G-4 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 627: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

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

SQL の CREATE TYPEおよび CREATE TYPE BODY文を使用します。型本体には、プロシージャとファンクションの両方を含めることができます。

ヒントヒントヒントヒント : これらの SQL 文を使用する際、元のバージョンを削除せずに頻繁に更新を行う場合は CREATE OR REPLACE文を使用する方が便利な場合があります。

無名ブロックの DECLARE部で PROCEDURE procedure_name IS...または FUNCTION function_name RETURN return_type IS...を定義します。これらのプロシージャおよびファンクションは、その無名ブロックの実行中のみ存在し、そのブロック内でのみ参照できます。この方法は、長時間実行の無名ブロックまたは広範囲な無名ブロックの場合に有効です。

別のプロシージャまたはファンクションの宣言部で PROCEDURE procedure_name IS...または FUNCTION function_name RETURN return_type IS...を定義します。これらのプロシージャおよびファンクションは、その外側のプロシージャ内でのみ参照できます。そのためこの方法を使用すると、名前空間が一杯になること、および他のサブプログラムからの不要なコールを防止できます。

PL/SQL を使用したデータの入力または出力を使用したデータの入力または出力を使用したデータの入力または出力を使用したデータの入力または出力PL/SQL のほとんどの I/O は、SQL 文によるデータベース表へのデータの格納や、それらの表の問合せによるものです。

PL/SQL のその他のすべての I/O は、他のプログラムと相互作用する API によるものです。たとえば、DBMS_OUTPUTパッケージには、PUT_LINEなどのプロシージャが含まれています。PL/SQL 外部の結果を参照するには、DBMS_OUTPUTに渡されたデータを読み取って表示するための、SQL*Plus などの別のプログラムが必要です。(SQL*Plus で DBMS_OUTPUTのデータを表示するには、事前に SET SERVEROUTPUT ONコマンドを発行しておく必要があります。)

I/O を実行する PL/SQL のその他の API は、HTP(Web ページへの出力の表示)、DBMS_PIPE(PL/SQL とオペレーティング・システム・コマンド間での情報の受渡し)、UTL_FILE(オペレーティング・システム・ファイルの読取りと書込み)、UTL_HTTP(Webサーバーとの通信)、UTL_SMTP(メール・サーバーとの通信)および TEXT_IO(Oracle Forms からのテキストの表示)です。

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

PL/SQL に関する FAQ G-5

Page 628: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

大 / 小文字を区別しない問合せの実行

大大大大 / 小文字を区別しない問合せの実行小文字を区別しない問合せの実行小文字を区別しない問合せの実行小文字を区別しない問合せの実行大 / 小文字を区別せずに VARCHAR2値と一致する問合せを行ういくつかの方法があります。たとえば、列の値に対して UPPER()または LOWER()ファンクションを実行し、その列にファンクション索引を作成します。または、表に新しい列を追加して、別の列値のコピーをすべて大文字またはすべて小文字で格納するトリガーを定義し、この新しい列を問い合せます。

今回のリリースからは、コードを変更せずに、大 / 小文字(さらにアクセント記号の有無)を区別しない問合せを実行できます。NLS_SORT初期化パラメータの通常の値に _CIを追加すると、問合せで大 / 小文字が区別されません。NLS_SORTパラメータの通常の値に _CIを追加すると、問合せでアクセント記号の有無が区別されません。

G-6 PL/SQL ユーザーズ・ガイドおよびリファレンス

Page 629: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

索引索引索引索引

記号記号記号記号

%BULK_EXCEPTIONS カーソル属性,11-17%BULK_ROWCOUNT カーソル属性,11-15%FOUND カーソル属性,6-8,6-21%ISOPEN カーソル属性,6-8,6-22%NOTFOUND カーソル属性,6-23%ROWCOUNT カーソル属性,6-8,6-23%ROWTYPE 属性,2-14

構文,13-157%TYPE 属性,2-12

構文,13-182:= 代入演算子,1-7|| 連結演算子,2-28. 項目のセパレータ,2-3<< ラベルのデリミタ,2-3.. 範囲演算子,2-3,4-11=、!=、<> および ~= 関係演算子,2-27<、>、<= および >= 関係演算子,2-27@ リモート・アクセスのインジケータ,2-3,2-16--1 行コメントのデリミタ,2-3; 文の終了記号,2-3,13-16- 減算 / 否定演算子,2-3

数字数字数字数字

1 行コメント,2-93 項演算子,2-23

AACCESS_INTO_NULL 例外,10-6AL16UTF16 文字コード化体系,3-11ALL 行演算子,6-3

ALTER TYPE 文型の発展,12-12

AUTHID 句,8-4,8-5,8-21AUTONOMOUS_TRANSACTION プラグマ,6-46

構文,13-8

BBETWEEN 比較演算子,2-28BFILE データ型,3-14BINARY_FLOAT および BINARY_DOUBLE データ型,

3-3計算集中型プログラム,11-24

BINARY_INTEGER データ型,3-3BLOB データ型,3-14BOOLEAN データ型,3-15BULK COLLECT 句,11-19

CCARDINALITY 演算子,5-21CASE_NOT_FOUND 例外,10-6CASE 式,2-32CASE 文,4-4

構文,13-18CHARACTER サブタイプ,3-6CHAR データ型,3-6

方法,B-1CLOB データ型,3-14CLOSE 文,6-17,6-33

構文,13-21COLLECTION_IS_NULL 例外,10-6COMMENT 句,6-39COMMIT 文,6-38

構文,13-37

索引索引索引索引 -1

Page 630: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

COUNT コレクション・メソッド,5-31CURRENT OF 句,6-43CURRVAL 疑似列,6-3CURSOR_ALREADY_OPEN 例外,10-6

DDATE データ型,3-16DBMS_ALERT パッケージ,9-15DBMS_OUTPUT パッケージ,9-15DBMS_PIPE パッケージ,9-16DBMS_WARNING パッケージ,10-24DECODE ファンクション

NULL の扱い,2-36DEC と DECIMAL サブタイプ,3-5DEFAULT キーワード,2-12DELETE コレクション・メソッド,5-38DELETE 文

構文,13-57DEPARTMENTS サンプル表,xxiiDEREF ファンクション,12-26DETERMINISTIC ヒント,8-5DISTINCT 行演算子,6-3,6-6DUP_VAL_ON_INDEX 例外,10-6

EELSE 句,4-3ELSIF 句,4-4EMPLOYEES サンプル表,xxiiEND IF 予約語,4-2END LOOP 予約語,4-10EXCEPTION_INIT プラグマ,10-9

RAISE_APPLICATION_ERROR での使用,10-11構文,13-60

EXECUTE IMMEDIATE 文,7-3EXECUTE 権限,8-23EXISTS コレクション・メソッド,5-31EXIT 文,4-8,4-15

WHEN 句,4-9構文,13-69使用できる場所,4-8

EXTEND コレクション・メソッド,5-35

FFALSE 値,2-8FETCH 文,6-15,6-32

構文,13-81FIRST コレクション・メソッド,5-32FLOAT サブタイプ,3-5FOR UPDATE 句,6-15

使用する場合,6-43制限,6-29

FORALL 文,11-10BULK COLLECT 句で使用,11-23構文,13-86

FOR ループ,4-11カーソル,6-12ネスト,4-14

GGOTO 文,4-16

構文,13-95ラベル,4-16例外ハンドラ内外への分岐,10-18

GROUP BY 句,6-3

HHR サンプル・スキーマ,xxiiHTML(Hypertext Markup Language),9-16HTTP(Hypertext Transfer Protocol),9-16

IIF 文,4-2

ELSE 句,4-3ELSIF 句,4-4THEN 句,4-2構文,13-97

IN OUT パラメータ・モード,8-11INDICES OF 句,11-10INSERT 文

構文,13-99レコード変数,5-46

INTERSECT 集合演算子,6-6INTERVAL DAY TO SECOND データ型,3-19INTERVAL YEAR TO MONTH データ型,3-19INTO 句,6-33

索引索引索引索引 -2

Page 631: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

INTO リスト,6-16INVALID_CURSOR 例外,10-6INVALID_NUMBER 例外,10-6IN パラメータ・モード,8-10IN 比較演算子,2-28IS A SET 演算子,5-21IS DANGLING 述語,12-26IS EMPTY 演算子,5-21IS NULL 比較演算子,2-27IS OF 述語,12-13

LLAST コレクション・メソッド,5-32LEVEL 疑似列,6-4LIKE 比較演算子,2-27LIMIT 句,11-22LIMIT コレクション・メソッド,5-32LOB(ラージ・オブジェクト)データ型,3-13LOB ロケータ,3-13LOCK TABLE 文,6-44

構文,13-105LOGIN_DENIED 例外,10-6LONG RAW データ型,3-7

大長,3-7変換,3-26

LONG データ型,3-7大長,3-7

制限,3-7LOOP 文,4-8

構文,13-107

MMEMBER OF 演算子,5-21MERGE 文

構文,13-113MINUS 集合演算子,6-6MULTISET EXCEPT 演算子,5-17MULTISET INTERSECT 演算子,5-17MULTISET UNION 演算子,5-17

NNational Language Support(NLS),3-11NATURAL と NATURALN サブタイプ,3-3NCHAR データ型,3-12

NCLOB データ型,3-14NEXTVAL 疑似列,6-3NEXT コレクション・メソッド,5-34NLS(National Language Support),3-11NO_DATA_FOUND 例外,10-7NOCOPY コンパイラ・ヒント

制限,11-27NOT NULL 制約

%TYPE 宣言の効果,2-13コレクション宣言での使用,5-13制限,6-14変数宣言で使用,2-12

NOT_LOGGED_ON 例外,10-7NOT 論理演算子

NULL の扱い,2-35NOWAIT パラメータ,6-43NULL の扱い,2-34

動的 SQL,7-13NULL 文,4-18

構文,13-114プロシージャで使用,8-4

NUMBER データ型,3-4NVARCHAR2 データ型,3-12NVL ファンクション

NULL の扱い,2-36

OOPEN-FOR-USING 文

構文,13-129OPEN-FOR 文,6-29

構文,13-126OPEN 文,6-15

構文,13-124OR キーワード,10-17OTHERS 例外ハンドラ,10-2,10-17OUT パラメータ・モード,8-10

PPARALLEL_ENABLE オプション,8-5PIPE ROW 文

段階的に行を戻す場合,11-40PLS_INTEGER データ型,3-5PL/SQL

Server Pages(PSP),8-29アーキテクチャ,1-16

索引索引索引索引 -3

Page 632: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

移植性,1-4エンジン,1-16言語要素の構文,13-1サンプル・プログラム,A-1制限,E-1パフォーマンス,1-3プロシージャ的な面,1-5ブロック

構文,13-11ブロック構造,1-6無名ブロック,1-6メリット,1-2予約語,F-1

PLSQL_CODE_TYPE 初期化パラメータ,11-30PLSQL_NATIVE_LIBRARY_DIR 初期化パラメータ,

11-30PLSQL_NATIVE_LIBRARY_SUBDIR_COUNT 初期化

パラメータ,11-30PLSQL_OPTIMIZE_LEVEL 初期化パラメータ,11-2PLSQL_WARNINGS 初期化パラメータ,10-24POSITIVEL と POSITIVEN サブタイプ,3-3PRIOR 行演算子,6-4,6-6PRIOR コレクション・メソッド,5-34PROGRAM_ERROR 例外,10-7

Rraise_application_error プロシージャ,10-10RAISE 文,10-12

構文,13-143例外ハンドラでの使用,10-16

RAW データ型,3-7大長,3-7

変換,3-26READ ONLY パラメータ,6-42RECORD データ型,5-41ref,12-21

参照解除,12-26参照先がない,12-26宣言,12-21

REF CURSOR データ型,6-25定義,6-26

REF CURSOR 変数事前定義の SYS_REFCURSOR 型,11-43テーブル・ファンクションへのパラメータ,11-43

REF 型修飾子,12-21REF ファンクション,12-25

REGEXP_INSTR ファンクション,G-2REGEXP_LIKE ファンクション,G-2REGEXP_REPLACE ファンクション,G-2REGEXP_SUBSTR ファンクション,G-2REPEAT UNTIL 構造

PL/SQL での等価,4-11REPLACE ファンクション

NULL の扱い,2-37RESTRICT_REFERENCES プラグマ,8-29

構文,13-150自律型ファンクションでの使用,6-51動的 SQL での使用,7-14

RETURNING 句,12-29レコード変数,5-48

RETURN 句カーソル,9-17ファンクション,8-5

RETURN 文,8-6構文,13-153

REVERSE 予約語,4-12ROLLBACK 文,6-38

構文,13-155セーブポイントへの影響,6-40

ROWID,3-8ROWIDTOCHAR ファンクション,6-4ROWID 疑似列,6-4ROWID データ型,3-8ROWNUM 疑似列,6-4ROWTYPE_MISMATCH 例外,10-7RPC(リモート・プロシージャ・コール),10-13

SSAVEPOINT 文,6-38

構文,13-159SCN_TO_TIMESTAMP ファンクション,13-160SELECT INTO 文

構文,13-162SELF パラメータ,12-8SERIALLY_REUSABLE プラグマ

構文,13-167Server Pages、PL/SQL,8-29SET TRANSACTION 文,6-41

構文,13-169SET 演算子,5-17SIGNTYPE サブタイプ,3-3

索引索引索引索引 -4

Page 633: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

SQLPL/SQL での発行,6-2疑似列,6-3データ操作文,6-2動的,7-2比較演算子,6-5

SQLCODE ファンクション,10-19構文,13-177

SQLERRM ファンクション,10-19構文,13-179

SQL カーソル構文,13-172

START WITH 句,6-4STEP 句

PL/SQL での等価,4-13STORAGE_ERROR 例外,10-7

呼び出される場合,8-27STRING サブタイプ,3-10SUBSCRIPT_BEYOND_COUNT 例外,10-7SUBSCRIPT_OUTSIDE_LIMIT 例外,10-7SUBSTR ファンクション,10-19SYS_REFCURSOR 型,11-43

TTABLE 演算子,5-27TABLE データ型,5-2THEN 句,4-2TIMEOUT_ON_RESOURCE 例外,10-7TIMESTAMP WITH LOCAL TIME ZONE データ型,

3-18TIMESTAMP WITH TIME ZONE データ型,3-17TIMESTAMP_TO_SCN ファンクション,13-181TIMESTAMP データ型,3-17TOO_MANY_ROWS 例外,10-7TREAT 演算子,12-13TRIM コレクション・メソッド,5-36TRUE 値,2-8

UUNION および UNION ALL 集合演算子,6-6UPDATE 文

構文,13-185レコード変数,5-47

URL(Uniform Resource Locator),9-16UROWID データ型,3-8

USING 句,7-3,13-67UTF8 文字コード化体系,3-11UTL_FILE パッケージ,9-16UTL_HTTP パッケージ,9-16

VVALUE_ERROR 例外,10-8VALUES OF 句,11-10VALUE ファンクション,12-25VARCHAR2 データ型,3-9

方法,B-1VARCHAR サブタイプ,3-10VARRAY

構文,13-29サイズの制限,5-8

VARRAY データ型,5-3

WWHEN 句,4-9,10-17WHILE ループ,4-10

ZZERO_DIVIDE 例外,10-8

ああああ

値方式によるパラメータの引渡し,8-30アドレス,6-25アポストロフィ,2-8アンダースコア,2-4暗黙カーソル

属性,6-7暗黙的な宣言

FOR ループ・カウンタ,4-14カーソル FOR ループのレコード,6-12

暗黙的なデータ型変換,3-23パフォーマンスへの影響,11-6

いいいい

移植性,1-4インスタンス,12-3

索引索引索引索引 -5

Page 634: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ええええ

エイリアシング,8-30エラー・メッセージ

大長,10-19演算子

関係,2-27比較,2-26優先順位,2-24

おおおお

オーダー・メソッド,12-9オーバーロード,8-12

オブジェクト・メソッド,12-9継承,8-18制限,8-15パッケージ・サブプログラム,9-13

オブジェクト共有,12-21初期化,12-16宣言,12-15操作,12-23

オブジェクト型,12-1,12-2構造,12-5構文,13-115定義,12-13メリット,12-4例,12-13

オブジェクト型の代替性,8-18オブジェクト・コンストラクタ

コール,12-19パラメータの受渡し,12-20

オブジェクト指向プログラミング,12-1オブジェクト属性,12-2,12-6

大数,12-6使用できるデータ型,12-6

オブジェクト表,12-24オブジェクト・メソッド,12-2,12-7

コール,12-20オプション、PARALLEL_ENABLE,8-5

かかかか

カーソルRETURN 句,9-17オープン,6-15

クローズ,6-17構文,13-53宣言,6-14パッケージ,9-17パラメータ付き,6-20フェッチ,6-15明示的,6-14有効範囲規則,6-14

カーソル FOR ループ,6-12パラメータの引渡し,6-20

カーソル式,6-35カーソル属性

%BULK_EXCEPTIONS,11-17%BULK_ROWCOUNT,11-15%FOUND,6-8,6-21%ISOPEN,6-8,6-22%NOTFOUND,6-23%ROWCOUNT,6-8,6-23値,6-24暗黙的,6-7構文,13-43

カーソル副問合せ,6-35カーソル変数,6-25

オープン,6-29クローズ,6-33構文,13-47制限,6-35宣言,6-26代入,6-34テーブル・ファンクションへのパラメータ,11-43フェッチ,6-32

改行,2-2解決、名前,D-1,2-17外部参照,8-21外部ルーチン,8-27科学表記法,2-6隠された宣言,9-2可視性

トランザクション,6-48パッケージの内容,9-2有効範囲,2-19

型定義

RECORD,5-41REF CURSOR,6-26コレクション,5-7先送り,12-23

型の継承,12-13

索引索引索引索引 -6

Page 635: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

型の発展,12-12カッコ,2-24各国語キャラクタ・セット,3-11各国語キャラクタ・データ型,3-11可読性,2-2,4-18仮パラメータ,6-21関係演算子,2-27

きききき

記憶域表,5-7疑似列,6-3

CURRVAL,6-3LEVEL,6-4NEXTVAL,6-3ROWID,6-4ROWNUM,6-4

規則、純正,8-29基本構造的に NULL,12-16基本ループ,4-8キャラクタ・セット,2-2行演算子,6-6行ロック,6-43

くくくく

句AUTHID,8-4,8-5,8-21BULK COLLECT,11-19LIMIT,11-22

空白使用できる場所,2-2

空白埋めの方法,B-2組込みファンクション,2-38位取り

指定,3-4

けけけけ

警告メッセージ,10-24継承,12-13

オーバーロード,8-18桁数精度,3-4結果セット,6-15結合配列,5-4

構文,13-29ネストした表との比較,5-6

言語間のコール,8-27検索 CASE 式,2-33

ここここ

後続する空白,B-3構文

PL/SQL の言語要素,13-1図の読み方,xxii

コール

言語間,8-27サブプログラム,8-9

コール仕様部,9-2コメント,2-9

構文,13-35制限,2-10

コレクション,5-2型の定義,5-7構文,13-29コンストラクタ,5-13参照,5-16種類,5-1初期化,5-13代入,5-17バルク・バインド,5-49,11-9比較,5-21変数の宣言,5-10マルチレベル,5-27有効範囲,5-7要素型,5-7

コレクションの例外呼び出される場合,5-40

コレクション・メソッド構文,13-23使用,5-30パラメータに適用,5-39

コンストラクタオブジェクト,12-11コレクション,5-13定義,12-18

コンテキストトランザクション,6-48

コンポジット型,3-2

索引索引索引索引 -7

Page 636: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ささささ

再帰,8-27サイズの制限、VARRAY,5-8

大サイズ

CHAR 値,3-6LOB,3-13LONG RAW 値,3-7LONG 値,3-7NCHAR 値,3-12NVARCHAR2 値,3-12Oracle エラー・メッセージ,10-19RAW 値,3-7VARCHAR2 値,3-9識別子,2-5大精度,3-4

先送り型定義,12-23作業領域、問合せ,6-25索引付き表「結合配列」を参照

サブタイプ,3-3,3-21,12-13CHARACTER,3-6DEC と DECIMAL,3-5FLOAT,3-5NATURAL と NATURALN,3-3POSITIVE と POSITIVEN,3-3SIGNTYPE,3-3STRING,3-10VARCHAR,3-10互換性,3-22制約と無制約,3-21定義,3-21

サブプログラム,8-2オーバーロード,8-12コールの解決方法,8-15再帰,8-27スタンドアロン,1-17ストアド,1-17宣言,8-7パッケージ,1-17プロシージャとファンクションの比較,8-4ローカル,1-17

参照、外部,8-21参照型,3-2参照先がない REF,12-26参照方式によるパラメータの引渡し,8-30サンプル・プログラム,A-1

しししし

式,2-23CASE,2-32構文,13-71ブール,2-29

識別子

構成,2-4大長,2-5

二重引用符で囲んだ,2-6有効範囲規則,2-19

字句単位,2-2システム固有の実行

PL/SQL プロシージャのコンパイル,11-28システム固有の実行のための PL/SQL プロシージャの

コンパイル,11-28システム固有の動的 SQL「動的 SQL」を参照

事前定義の例外再宣言,10-11明示的な呼出し,10-12リスト,10-5

実行者権限,8-20実行部

PL/SQL ブロック,1-6ファンクション,8-5プロシージャ,8-4

実パラメータ,6-21集計関数

PL/SQL,6-3集計代入,2-14集合演算子,6-6修飾子

サブプログラム名を使用,2-18必要な場合,2-16,2-21

終了記号、文,2-3述語,6-5順序,6-3純正規則,8-29条件制御,4-2照合順番,2-29仕様部

オブジェクト,12-5カーソル,9-17コール,9-2パッケージ,9-5ファンクション,8-5

索引索引索引索引 -8

Page 637: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

プロシージャ,8-4メソッド,12-7

初期化DEFAULT の使用,2-12オブジェクト,12-16コレクション,5-13パッケージ,9-8必要な場合,2-12変数,2-22

書式

マスク,3-25自律型トランザクション

PL/SQL,6-45自律型トリガー,6-50新機能,xxiii

すすすす

数値リテラル,2-6スーパータイプ,12-13スカラー・データ型,3-2スタンドアロン・サブプログラム,1-17ストアド・サブプログラム,1-17

せせせせ

正規表現,G-2制御構造,4-2

順次,4-15条件,4-2反復,4-8

制限、PL/SQL,E-1制限 ROWID,3-8生産性,1-4精度桁数

指定,3-4制約

NOT NULL,2-12セーブポイント名

再利用,6-40セパレータ,2-3宣言

オブジェクト,12-15カーソル,6-14カーソル変数,6-26コレクション,5-10サブプログラム,8-7

定数,2-11変数,2-11例外,10-8

宣言部

PL/SQL ブロック,1-6ファンクション,8-5プロシージャ,8-4

選択子,2-32前方参照,2-16前方宣言,8-7

そそそそ

相関副問合せ,6-19属性

%ROWTYPE,2-14%TYPE,2-12オブジェクト,12-2,12-6カーソル,6-21

疎コレクション,5-3

たたたた

大 / 小文字の区別

識別子,2-5文字列リテラル,2-8

大 / 小文字を区別しない問合せ,G-6代入

カーソル変数,6-34コレクション,5-17集計,2-14フィールド,5-45方法,B-2文字列,B-2レコード,5-45

代入演算子,1-7代入文

構文,13-4タブ,2-2単項演算子,2-23短絡評価,2-26

てててて

定義者権限,8-20定数

構文,13-39

索引索引索引索引 -9

Page 638: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

宣言,2-11データ型,3-1

BFILE,3-14BINARY_INTEGER,3-3BLOB,3-14BOOLEAN,3-15CHAR,3-6CLOB,3-14DATE,3-16INTERVAL DAY TO SECOND,3-19INTERVAL YEAR TO MONTH,3-19LONG,3-7LONG RAW,3-7NCHAR,3-12NCLOB,3-14NUMBER,3-4NVARCHAR2,3-12PLS_INTEGER,3-5RAW,3-7RECORD,5-41REF CURSOR,6-25ROWID,3-8TABLE,5-2TIMESTAMP,3-17TIMESTAMP WITH LOCAL TIME ZONE,3-18TIMESTAMP WITH TIME ZONE,3-17UROWID,3-8VARCHAR2,3-9VARRAY,5-3暗黙的な変換,3-23各国語キャラクタ,3-11グループ,3-2スカラーとコンポジット,3-1

データベース・キャラクタ・セット,3-11データベース・トリガー,1-18

自律型,6-50テーブル・ファンクション,11-36

問合せ,11-42デッドロック

PL/SQL による処理,6-39デフォルトのパラメータ値,8-12デリミタ,2-3伝播、例外,10-13

とととと

問合せ

大 / 小文字の区別なし,G-6問合せ作業領域,6-25動的 SQL,7-2

EXECUTE IMMEDIATE 文の使用方法,7-3動的 SQL 活用時のヒント,7-10

ドット表記法,1-8オブジェクト属性,12-17オブジェクト・メソッド,12-20グローバル変数,4-14コレクション・メソッド,5-30パッケージ内容,9-6

トランザクション,6-2可視性,6-48コミット,6-38コンテキスト,6-48処理,6-2,6-38自律型

PL/SQL,6-45適切な終了,6-41読取り専用,6-41ロールバック,6-38

トリガー,1-18自律型,6-50

なななな

名前

カーソル,6-14修飾,2-16セーブポイント,6-40変数,2-17

名前解決,2-17,D-1

にににに

二重引用符で囲んだ識別子,2-6日時リテラル,2-9ニブル,3-26入力 ROWID,3-8

索引索引索引索引 -10

Page 639: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

ねねねね

ネーミング規則,2-16ネスト

FOR ループ,4-14オブジェクト,12-7ブロック,1-6レコード,5-43

ネストしたカーソル,6-35ネストしたコレクション,5-27ネストした表

結合配列との比較,5-6構文,13-29操作,5-23

はははは

バイナリ演算子,2-23パイプ,9-16パイプライン化

定義,11-37バインド,11-9パターン一致,2-28パッケージ,9-1,9-2

構文,13-132参照,9-6仕様部,9-2初期化,9-8製品固有,9-15プライベート・オブジェクトとパブリック・オブ

ジェクトの比較,9-13本体,9-2本体なし,9-6メリット,9-4有効範囲,9-5

パッケージ・カーソル,9-17パッケージ・サブプログラム,1-17

オーバーロード,9-13コール,9-6

ハッシュ表

結合配列でのシミュレート,5-5パフォーマンス,1-3パブリック・オブジェクト,9-13パラメータ

SELF,12-8カーソル,6-20実と仮の対比,8-8

デフォルト値,8-12モード,8-10

パラメータのエイリアシング,8-30パラメータの引渡し

値方式,8-30参照方式,8-30動的 SQL,7-5

バルク・バインド,11-9バルク・フェッチ,11-20バルク・リターン,11-23範囲演算子,4-11ハンドラ、例外,10-2

ひひひひ

比較

コレクション,5-21式の比較,2-29文字値,B-2

比較演算子,2-26,6-5非空白埋めの方法,B-3日付

TO_CHAR デフォルトの書式,3-25変換,3-25

非同期操作,9-15評価

短絡,2-26評価の順序,2-24,2-25表記法

位置表記法と名前表記法の対比,8-9ヒント、DETERMINISTIC,8-5

ふふふふ

ファイル I/O,9-16ファンクション,8-1

RETURN 句,8-5組込み,2-38構文,13-90コール,8-6仕様部,8-5パラメータ,8-4部分,8-5本体,8-5

フィールド,5-41ブール式,2-29ブール・リテラル,2-8

索引索引索引索引 -11

Page 640: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

フェッチバルク,11-20複数のコミット,6-44

不完全なオブジェクト型,12-23副作用,8-10

制御,8-29複数行コメント,2-10副問合せ,6-18物理 ROWID,3-8プライベート・オブジェクト,9-13プラグマ,10-9

AUTONOMOUS_TRANSACTION,6-46EXCEPTION_INIT,10-9RESTRICT_REFERENCES,6-51,7-14,8-29

プレースホルダ,7-2重複,7-12

プログラム・ユニット,1-12プロシージャ,8-1

構文,13-138コール,8-4仕様部,8-4パラメータ,8-3部分,8-4本体,8-4

ブロックPL/SQL,13-11構造,1-6ラベル,2-21

文、PL/SQLCASE,13-18CLOSE,6-17,6-33,13-21COMMIT,13-37DELETE,13-57EXECUTE IMMEDIATE,7-3EXIT,13-69FETCH,6-15,6-32,13-81FORALL,11-10GOTO,13-95IF,13-97INSERT,13-99LOCK TABLE,13-105LOOP,13-107MERGE,13-113NULL,13-114OPEN,6-15,13-124OPEN-FOR,6-29,13-126RAISE,13-143

RETURN,13-153ROLLBACK,13-155SAVEPOINT,13-159SELECT INTO,13-162SET TRANSACTION,13-169UPDATE,13-185代入,13-4動的 SQL,7-2

文の終了記号,13-16文レベルのロールバック,6-39

へへへへ

ベース型,3-3,3-21変換

ファンクション,3-24変換、データ型,3-23変数

値の代入,2-22グローバル,9-10構文,13-39初期化,2-22宣言,2-11

ほほほほ

ポインタ,6-25方法

空白埋め,B-2代入,B-2非空白埋め,B-3文字列の比較,B-2

ホスト配列バルク・バインド,11-24

本体オブジェクト,12-5カーソル,9-17パッケージ,9-7ファンクション,8-5プロシージャ,8-4メソッド,12-7

まままま

マップ・メソッド,12-9マルチレベル・コレクション,5-27

索引索引索引索引 -12

Page 641: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

みみみみ

未初期化オブジェクト

処理方法,12-16未処理例外,10-13,10-20密コレクション,5-3

むむむむ

無限ループ,4-8無名ブロック,1-6

めめめめ

明示カーソル,6-14メソッド

オブジェクト,12-2,12-7コレクション,5-30順序付け,12-9マップ,12-9

メソッドのオーバーライド,12-13メソッドのコール、連鎖,12-20メンバーかどうかのテスト,2-28

もももも

モード、パラメータIN,8-10IN OUT,8-11OUT,8-10

文字値選択,B-4挿入,B-3代入,B-2比較,B-2

モジュール性,1-12,9-4文字リテラル,2-7文字列の比較方法,B-2文字列リテラル,2-8戻り型,6-26,8-15戻り値、ファンクション,8-5

ゆゆゆゆ

有効範囲,2-19カーソル,6-14カーソル・パラメータ,6-15

コレクション,5-7識別子,2-19定義,2-19パッケージ,9-5ループ・カウンタ,4-13例外,10-8

ユーザー定義のサブタイプ,3-21ユーザー定義の例外,10-8ユーザー定義のレコード,5-41優先順位、演算子,2-24ユニバーサル ROWID,3-8

よよよよ

要素型、コレクション,5-7呼出し、例外,10-12読取り専用トランザクション,6-41予約語,2-5,F-1

らららら

ラージ・オブジェクト(LOB)データ型,3-13ラップ・ユーティリティ,C-1ラベル

GOTO 文,4-16ブロック,2-21ループ,4-10

ランタイム・エラー,10-1

りりりり

リテラル,2-6構文,13-102数値,2-6日時,2-9ブール,2-8文字,2-7文字列,2-8

リモート・アクセスのインジケータ,2-16

るるるる

ルーチン、外部,8-27ループ

カウンタ,4-11ラベル,4-10

索引索引索引索引 -13

Page 642: PL/SQLユーザーズ・ガイドおよびリファレンス, …otndnld.oracle.co.jp/document/products/oracle10g/101/doc...Oracle Database 10 g のPL/SQL の新機能 ..... xxiv Oracle9i

れれれれ

例外,10-2RAISE 文での呼出し,10-12WHEN 句,10-17構文,13-62再呼出し,10-16事前定義,10-5宣言,10-8宣言の中での呼出し,10-18伝播,10-13ハンドラでの呼出し,10-18有効範囲規則,10-8ユーザー定義,10-8

例外処理,10-1OTHERS ハンドラの使用,10-17宣言の中での呼出し,10-18ハンドラでの呼出し,10-18

例外処理部PL/SQL ブロック,1-6ファンクション,8-5プロシージャ,8-4

例外の再呼出し,10-16例外ハンドラ,10-17

OTHERS ハンドラ,10-2RAISE 文の使用,10-16SQLCODE ファンクションの使用,10-19SQLERRM ファンクションの使用,10-19

レコード,5-41%ROWTYPE,6-13RETURNING INTO 句,5-48SQL の INSERT 文および UPDATE 文,6-9暗黙的な宣言,6-13更新,5-47構文,13-145コレクションのバルク・バインド,5-49操作,5-43挿入,5-46挿入 / 更新に関する制約,5-49代入,5-45定義,5-41ネスト,5-43比較,5-46

列の別名,6-13必要な場合,2-15

連結演算子,2-28NULL の扱い,2-36

ろろろろ

ローカル・サブプログラム,1-17ロールバック

FORALL 文,11-15暗黙的,6-41文レベル,6-39

ロケータ変数,10-22ロック,6-38

FOR UPDATE 句の使用,6-43上書き,6-42モード,6-38

論理 ROWID,3-8

わわわわ

ワイルドカード,2-28

索引索引索引索引 -14