Oracle® Database

オブジェクト・リレーショナル開発者ガイド

11gリリース2 (11.2)

E94920-01(原本部品番号:E11822-05)

2013年7月

Oracle Databaseオブジェクト・リレーショナル開発者ガイド, 11gリリース2 (11.2)

E94920-01

Copyright © 1996, 2013, Oracle and/or its affiliates. All rights reserved.

原本協力者: Sundeep Abraham、Shashaanka Agrawal、Geeta Arora、Eric Belden、Janis Greenberg、Chandrasekharan Iyer、Geoff Lee、Anand Manikutty、Valarie Moore、Magdi Morsi、Helen Yeh、Adiel Yoaz、Qin Yu

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントが、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供される場合は、次のNoticeが適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

このソフトウェアまたはハードウェアおよびドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

目次

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

オブジェクト・リレーショナルの新機能

- Oracle Database 11gリリース2 (11.2)のオブジェクト・リレーショナル機能の新機能

- Oracle Database 11gリリース1(11.1)のオブジェクト・リレーショナル機能の新機能

- Oracle Database 10gリリース1(10.1)のオブジェクト・リレーショナル機能の新機能

1 Oracleオブジェクトの概要

- Oracleオブジェクトの概要

- オブジェクトの利点

- オブジェクト・リレーショナル・モデルの主な機能

- Oracleオブジェクトのデータベース機能

- オブジェクト型について

- オブジェクト・インスタンスについて

- オブジェクト・メソッドについて

- オブジェクトを表に格納する方法

- オブジェクト識別子による行オブジェクトの識別

- 行オブジェクトの参照の使用

- Oracleコレクションの使用

- オブジェクト・ビューによるリレーショナル・データへのアクセス

- 型継承の使用

- 型進化による既存のオブジェクト型の変更

- Oracleオブジェクトの言語にバインドされた機能

2 Oracleオブジェクトの基本コンポーネント

- SQLオブジェクト型および参照

- NULLオブジェクトおよび属性

- 文字長セマンティクス

- オブジェクト表の制約

- オブジェクト表の索引

- オブジェクト表のトリガー

- REF型の列および属性のルール

- 名前解決

- 表別名が必要な場合

- リモート・データベースでユーザー定義型を使用する際の制限事項

- オブジェクト・メソッド

- メンバー・メソッド

- メンバー・メソッド内のSELFパラメータ

- オブジェクトを比較するためのメンバー・メソッド

- 静的メソッド

- コンストラクタ・メソッド

- システム定義コンストラクタ

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

- コンストラクタ・メソッドのリテラル起動

- 外部実装メソッド

- SQLオブジェクト型の継承

- スーパータイプおよびサブタイプ

- FINALとNOT FINALの型およびメソッドの定義

- サブタイプの作成

- 親オブジェクトまたはスーパータイプ・オブジェクトの作成

- サブタイプのオブジェクトの作成

- 一般的な起動

- 複数のサブタイプ

- スーパータイプおよびサブタイプのオブジェクトを持つ表の作成

- NOT INSTANTIABLEとしての型およびメソッドの宣言

- メソッドのオーバーロードおよびオーバーライド

- メソッドのオーバーロード

- メソッドのオーバーライドおよび隠蔽

- メソッドのオーバーライドの制限事項

- 動的メソッド・ディスパッチ

- 型階層内の型の代入

- 列および行の代入性

- 代入可能な行でのOBJECT_VALUEおよびOBJECT_IDの使用

- スーパータイプの属性を持つサブタイプ

- REF列および属性の代入

- コレクション要素の代入

- 新しく作成したサブタイプの代入可能な列への格納

- 代入可能な列の作成後のサブタイプの削除

- 新しい表での代入性の無効化

- 代入性の制約

- 代入性の変更

- 代入性の変更の制限事項

- 型をまたがる代入

- オブジェクト代入の代表的なオブジェクト

- ナローイング代入

- コレクションの代入

- オブジェクトに便利なファンクションおよび演算子

- CAST

- CURSOR

- DEREF

- IS OF type

- REF

- SYS_TYPEID

- TABLE()

- TREAT

- ナローイング代入でのTREATの使用

- サブタイプの属性またはメソッドにアクセスするためのTREATファンクションの使用

- VALUE

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

- PL/SQLでのオブジェクトの宣言と初期化

- オブジェクト型の定義

- PL/SQLブロックでのオブジェクトの宣言

- PL/SQLでの未初期化オブジェクトの処理規則

- PL/SQLでのオブジェクトの操作

- ドット表記法によるオブジェクト属性へのアクセス

- オブジェクトのコンストラクタとメソッドに対するコール

- オブジェクトの更新および削除

- REF修飾子によるオブジェクトの操作

- 継承を使用するPL/SQLでのオーバーロードの使用

- オブジェクトでの動的SQLの使用

4 Oracleプログラム環境のオブジェクト・サポート

- SQLおよびオブジェクト型

- SQL Developer

- PL/SQL

- Oracle Call Interface(OCI)

- OCIプログラムにおける連想アクセス

- OCIプログラムのナビゲーショナル・アクセス

- オブジェクト・キャッシュ

- オブジェクトを操作するOCIプログラムの作成

- Cでのユーザー定義コンストラクタの定義

- Pro*C/C++

- Pro*C/C++での連想アクセス

- Pro*C/C++でのナビゲーショナル・アクセス

- Oracleのオブジェクト型とC言語のデータ型の間の変換

- Oracle Type Translator(OTT)

- Oracle C++ Call Interface(OCCI)

- OCCI結合リレーショナルおよびオブジェクト・インタフェース

- OCCIナビゲーショナル・インタフェース

- Oracle Objects for OLE(OO4O)

- Visual Basicでのオブジェクトの表現形式(OraObject)

- Visual BasicでのREFの表現形式(OraRef)

- Visual BasicでのVARRAYおよびネストした表の表現形式(OraCollection)

- OracleオブジェクトにアクセスするJavaツール

- Oracleオブジェクト・データへのJDBCアクセス

- Oracleオブジェクト・データへのSQLJアクセス

- データ・マッピング方法の選択

- JPublisher

- JPublisherを使用したJDBCおよびSQLJプログラム用Javaクラスの作成

- ユーザー定義のオブジェクト型に対してJPublisherで生成される内容

- Javaオブジェクトの記憶域

- サーバーに対するSQLJ型の表現

- SQLJオブジェクト型の作成

- マッピングに関するその他の注意

- SQLJ型の進化

- 制約

- SQLJオブジェクトの問合せ

- Javaオブジェクトの挿入

- SQLJオブジェクトの更新

- Javaでのユーザー定義コンストラクタの定義

- JDeveloper

- アプリケーション開発フレームワーク(ADF)

- TopLink

- XML

- オブジェクトをサポートするユーティリティ

- オブジェクト型のインポート/エクスポート

- タイプ

- オブジェクト・ビューの階層

- SQL*Loader

5 コレクション・データ型のサポート

- コレクション・データ型

- コレクション型の作成

- VARRAYまたはネストした表のインスタンスの作成

- コレクションのコンストラクタ・メソッド

- VARRAY

- ネストした表

- ネストした表の要素の格納

- ネストした表の格納時の表領域の指定

- VARRAYおよびネストした表要素のサイズおよび精度の増加

- VARRAYの制限サイズの増加

- LOB参照が含まれているVARRAYの作成

- マルチレベル・コレクション型

- マルチレベル・コレクション型のネストした表の記憶表

- マルチレベル・コレクションのVARRAY記憶域

- マルチレベル・コレクションのコンストラクタ

- コレクション・データ型の操作

- コレクションの問合せ

- コレクション問合せの結果のネスト化

- コレクション問合せの結果のネスト解除

- TABLE式の副問合せが含まれている問合せのネスト解除

- マルチレベル・コレクションを伴う問合せのネスト解除

- コレクションを対象としたDML操作の実行

- ネストした表を対象にしたピース単位操作

- マルチレベルのネストした表を対象にしたピース単位操作

- VARRAYおよびネストした表を対象にしたアトミック変更

- 基本データ単位としてのコレクション

- 結果セット全部を戻すためのBULK COLLECTの使用

- ネストした表を比較する条件

- 等価および非等価比較

- IN比較

- 多重集合比較のサブセット

- ネストした表のメンバー比較

- Empty比較

- Set比較

- ネストした表の多重集合操作

- CARDINALITY

- COLLECT

- MULTISET EXCEPT

- MULTISET INTERSECT

- MULTISET UNION

- POWERMULTISET

- POWERMULTISET_BY_CARDINALITY

- SET

- Oracleオブジェクトを持つ表のパーティション化

6 オブジェクト・モデルのリレーショナル・データへの適用

- オブジェクト・ビュー使用の利点

- オブジェクト・ビューの定義

- アプリケーションにおけるオブジェクト・ビューの使用

- オブジェクト・ビューにおけるオブジェクトのネスト

- オブジェクト・ビューにおけるNULLオブジェクトの識別

- オブジェクト・ビューにおけるネストした表およびVARRAYの使用

- オブジェクト・ビューのシングルレベル・コレクション

- オブジェクト・ビューのマルチレベル・コレクション

- オブジェクト・ビューに対するオブジェクト識別子の指定

- オブジェクトを表示するための参照の作成

- オブジェクト・ビューを利用した逆リレーションシップのモデル化

- オブジェクト・ビューの更新

- ビューにおけるネストした表列の更新

- 変更および妥当性チェックを制御するINSTEAD OFトリガーの使用

- オブジェクト・モデルのリモート表への適用

- オブジェクト・ビューにおける複雑なリレーションシップの定義

- 循環参照を示す表および型

- 循環参照を持つオブジェクト・ビューの作成

- オブジェクト・ビューの階層

- オブジェクト・ビュー階層の作成

- フラット・モデル

- 水平モデル

- 垂直モデル

- 階層内のビューの問合せ

- ビュー階層についての操作の権限

7 Oracleオブジェクトの管理

- オブジェクト型およびそれらのメソッドの権限

- オブジェクト型のシステム権限

- スキーマ・オブジェクト権限

- 新しい型または表での型の使用

- 例: オブジェクト型の権限

- オブジェクト、型および表のアクセス権限

- 型依存性

- 不完全な型の作成

- 不完全な型の再定義

- 手動による型の再コンパイル

- 型および表の依存性がある場合のCREATE OR REPLACE TYPEの使用

- 代入可能な表および列の型依存性

- DROP TYPE FORCEオプション

- オブジェクト型のシノニム

- 型のシノニムの作成

- 型のシノニムの使用

- シノニムを使用するスキーマ・オブジェクトの記述

- 型のシノニムへの依存

- 型のシノニムを置換する際の制限事項

- 型のシノニムの削除

- 型のシノニムの名前変更

- 型のパブリック・シノニムおよびローカル・スキーマ・オブジェクト

- パフォーマンス・チューニング

8 Oracleオブジェクトの高度なトピック

- オブジェクトの記憶域

- リーフ・レベル属性

- 列にまたがって分割される行オブジェクト

- 列オブジェクトを持つ表の非表示列

- 代入可能な列およびオブジェクト表の非表示列

- REFの記憶域

- ネストした表の内部レイアウト

- VARRAYの内部レイアウト

- 型IDまたは属性の索引作成

- 型判別式の列の索引付け

- 代入可能なサブタイプの索引付け

- 型進化

- 型進化および依存スキーマ・オブジェクト

- データを更新するオプション

- 型への構造的な変更の影響

- 属性の追加および削除による型の変更

- ネストした表属性の追加による型の変更

- 変更された型の妥当性チェック

- 型の変更の妥当性チェックに失敗した場合

- 型進化に使用するALTER TYPE文

- 型進化に使用するALTER TABLE文

- システム定義およびユーザー定義コンストラクタ

- 属性値コンストラクタ

- コンストラクタと型進化

- ユーザー定義コンストラクタの利点

- ユーザー定義コンストラクタの定義および実装

- コンストラクタのオーバーロードおよび隠蔽

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

- SQLJオブジェクト型のコンストラクタ

- 一時型および汎用型

- ユーザー定義集計ファンクション

- ロケータでネストした表のパフォーマンスを向上させる方法

9 Oracleオブジェクトの設計上の考慮点

- オブジェクトの記憶域上の一般的な考慮点

- 列または行としてのオブジェクトの格納

- リレーショナル表の列オブジェクトの記憶域

- オブジェクト表の行オブジェクトの記憶域

- オブジェクト識別子(OID)の記憶域上の考慮点

- システム生成のオブジェクト識別子(OID)

- 主キー・ベースのオブジェクト識別子(OID)

- システム生成のOIDと主キー・ベースのOID

- オブジェクト比較のパフォーマンス

- REFの設計上の考慮点

- REFの記憶域サイズ

- REF列に対する整合性制約

- 有効範囲付きREFのパフォーマンスおよび記憶域に関する考慮点

- 有効範囲付きREFの索引付け

- WITH ROWIDオプションを使用したオブジェクト・アクセスの高速化

- コレクションの設計上の考慮点

- ネストを解除する問合せを使用したリレーショナル形式でのオブジェクト・データの表示

- ネストを解除する問合せでのプロシージャおよびファンクションの使用

- VARRAYの記憶域上の考慮点

- VARRAYのサイズ変更の伝播

- VARRAYおよびネストした表のパフォーマンス

- ネストした表の設計上の考慮点

- ネストした表の記憶域

- ネストした表の索引

- ネストした表のロケータ

- セット・メンバーシップ問合せの最適化

- マルチレベル・コレクションの設計上の考慮点

- メソッドの設計上の考慮点

- メソッド・ファンクションに対する言語の選択

- 静的メソッド

- メンバー・プロシージャでのSELF IN OUT NOCOPYの使用

- タイプ・メソッドの戻り値に基づくファンクション索引

- 実行者権限を使用した再利用コードの作成

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

- オブジェクト表およびオブジェクト列のレプリケーション

- オブジェクト型、コレクション型またはREF型の列のレプリケーション

- オブジェクト表のレプリケーション

- オブジェクトに対する制約

- 型進化に関する考慮点

- 型の変更のクライアントへの送信

- デフォルトのコンストラクタの変更

- 型のFINALプロパティの変更

- Oracleオブジェクトでのパラレル問合せ

- 設計上の考慮点のヒントおよび技法

- 型進化かサブタイプの作成かの決定

- ANYDATAとユーザー定義型の相違点

- ポリモフィック・ビュー: オブジェクト・ビュー階層の代入

- SQLJオブジェクト型

- SQLJオブジェクト型の使用目的

- SQLJオブジェクト型作成時に実行されるアクション

- SQLJオブジェクト型の用途

- カスタム・オブジェクト型の用途

- SQLJオブジェクト型とJDBCを使用したカスタム・オブジェクト型の相違点

- その他の設計ヒント

- 階層内の列の置換え可能性と属性の数

- 型間の循環的依存関係

A オブジェクト・リレーショナル機能を使用したサンプル・アプリケーション

- サンプル・アプリケーションの概要

- リレーショナル・モデルに基づくスキーマの実装

- エンティティとリレーションシップ

- リレーショナル・モデルに基づく表の作成

- Customer_reltab

- PurchaseOrder_reltab

- Stock_reltab

- LineItems_reltab

- リレーショナル・モデルに基づく値の挿入

- リレーショナル・モデルに基づくデータの問合せ

- リレーショナル・モデルに基づくデータの更新

- リレーショナル・モデルに基づくデータの削除

- オブジェクト・リレーショナル・モデルに基づくスキーマの実装

- 型の定義

- メソッド定義

- getPONoメソッド

- sumLineItemsメソッド

- compareCustOrdersメソッド

- オブジェクト表の作成

- オブジェクト表Customer_objtab

- オブジェクト表のテンプレートとしてのオブジェクト・データ型

- オブジェクト識別子および参照

- 埋込みオブジェクトを持つオブジェクト表

- オブジェクト表Stock_objtab

- オブジェクト表PurchaseOrder_objtab

- 値の挿入

- 問合せ

- 削除

- オブジェクト型の進化

- Customer型への属性の追加

- マルチレベル・コレクションの操作

- ネストした表への挿入

- 明細項目を含む新規発注書の挿入

- マルチレベルのネストした表の問合せ

- 型の継承と代入可能な列

- サブタイプの作成

- サブタイプの挿入

- 代入可能な列の問合せ

用語集

索引

はじめに

『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』では、Oracle Database 11gリリース1 (11.1)のオブジェクト・リレーショナル機能の使用方法について説明します。このマニュアルの内容は、すべてのプラットフォームで動作するOracle Databaseのバージョンに適用されますが、システム固有の情報は含みません。

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

対象読者

『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』は、Oracle環境で実行するための新規アプリケーションの開発または既存のアプリケーションの変換を行うプログラマを対象としています。オブジェクト・リレーショナル機能は、コンテンツ管理、データ・ウェアハウス、データ/情報統合および複雑な構造のデータを処理するアプリケーションでよく使用されます。オブジェクト・ビュー機能は、既存のリレーショナル・スキーマ上に新しいC++、C#、JavaまたはXMLアプリケーションを作成する場合に役立ちます。

このマニュアルは、アプリケーション・プログラミングの実践的な知識があり、Structured Query Language (SQL)を使用してリレーショナル・データベース内の情報にアクセスする操作を理解していることを前提としています。『Oracle Database SQL言語クイック・リファレンス』、『Oracle Database PL/SQL言語リファレンス』および『Oracle Database 2日で開発者ガイド』の情報と、オブジェクト指向プログラミング手法を熟知している必要があります。

ドキュメントのアクセシビリティについて

オラクル社のアクセシビリティへの取組みの詳細は、Oracle Accessibility ProgramのWebサイトhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=docaccを参照してください。

Oracleサポートへのアクセス

Oracleのお客様は、My Oracle Supportにアクセスして電子サポートを受けることができます。詳細は、http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info、聴覚に障害があるお客様はhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trsを参照してください。

関連ドキュメント

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

- 『Oracle Database概要』には、Oracleの基本概念が説明されています。

- 『Oracle Database SQL言語リファレンス』および『Oracle Database管理者ガイド』には、SQLに関する情報が記載されています。

- 『Oracle Database PL/SQL言語リファレンス』には、Oracle SQLの手続き型言語拡張機能であるPL/SQLが詳しく説明されています。

- 『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』には、アプリケーションの開発に関する一般的な情報が説明されています

- 『Oracle Database JDBC開発者ガイドおよびリファレンス』および『Oracle Database Java開発者ガイド』には、Javaを使用するOracleのオブジェクト・リレーショナル機能について説明されています

- 『Oracle Call Interfaceプログラマーズ・ガイド』および『Oracle C++ Call Interfaceプログラマーズ・ガイド』には、1つ以上のOracleデータベースと対話する3GLアプリケーションをOracle Call Interface (OCI)およびOracle C++ Call Interface (OCCI)により作成する方法が説明されています。

- 『Pro*C/C++プログラマーズ・ガイド』は、オラクル社のプリコンパイラPro*シリーズの説明書です。このシリーズを使用することで、Ada、C、C++、COBOL、FORTRANのいずれかで書かれた3GLアプリケーション・プログラムにSQLおよびPL/SQLを組み込むことができます。

- 『Oracle XML DB開発者ガイド』および『Oracle XML Developer's Kitプログラマーズ・ガイド』には、XMLを使用したアプリケーション開発に関する一般的な情報が記載されています。

- 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』には、ラージ・オブジェクト(LOB)が詳しく説明されています。

- Oracle Data Provider for .NET開発者ガイド

- Oracle Developer Tools for Visual Studioヘルプ

このマニュアルの例の多くは、Oracle Databaseのインストール時に基本インストール・オプションを選択した場合にデフォルトでインストールされるサンプル・スキーマを使用しています。これらのスキーマがどのように作成されているか、およびその使用方法については、『Oracle Databaseサンプル・スキーマ』を参照してください。

無料のリリース・ノート、インストール・ドキュメント、ホワイト・ペーパーまたはその他の資料をダウンロードするには、Oracle Technology Network (OTN).を参照してください。OTN-Jを使用するには、オンラインでの登録が必要です。登録は、次のWebサイトから無償で行えます。

http://www.oracle.com/technetwork/index.html

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

http://www.oracle.com/technetwork/documentation/index.html

表記規則

このマニュアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するグラフィカル・ユーザー・インタフェース要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック

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

固定幅

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

オブジェクト・リレーショナルの新機能

この項では、Oracle 11gリリース1(11.1)のオブジェクト・リレーショナルの新機能について説明します。また、現行リリースにアップグレードするユーザーのために、前リリースでの新機能情報も含まれています。

次の各項で、Oracleのオブジェクト・リレーショナルの新機能について説明します。

- Oracle Database 11gリリース2 (11.2)のオブジェクト・リレーショナル機能の新機能

- Oracle Database 11gリリース1(11.1)のオブジェクト・リレーショナル機能の新機能

- Oracle Database 10gリリース1(10.1)のオブジェクト・リレーショナル機能の新機能

Oracle Database 11gリリース2 (11.2)のオブジェクト・リレーショナル機能の新機能

CREATE OR REPLACE TYPE文にFORCEオプションが追加されました

CREATE OR REPLACE TYPE文にFORCEオプションが追加され、型に依存している場合でも、型を置換できるようになりました。これは、FORCEオプションがないと機能しません。

関連項目:
「型および表の依存性がある場合のCREATE OR REPLACE TYPEの使用」

Oracle Database 11gリリース1(11.1)のオブジェクト・リレーショナル機能の新機能

一般的な起動のサポート

新たに一般的な起動の構文がサポートされました。したがって、サブタイプのメンバー・メソッドは、現在のサブタイプのスーパータイプ階層内にある任意のスーパータイプ(1つ上位のスーパータイプを含む)のメンバー・メソッドを静的に起動(ディスパッチ)できます。「一般的な起動」を参照してください。

Oracle Database 10gリリース1(10.1)のオブジェクト・リレーショナル機能の新機能

Oracle 10gリリース1(10.1)のオブジェクト・リレーショナルの新機能には、次のコレクションの拡張があります。

ネストした表およびVARRAY記憶域

ネストした表およびVARRAY記憶域用の新規機能。VARRAYサイズの進化、およびネストした表の格納時の表領域の指定が含まれています。「コレクション・データ型」を参照してください。

ネストした表の比較およびANSI SQL多重集合操作

ネストした表の比較、およびネストした表のANSI SQL多重集合操作の新機能。「コレクション・データ型の操作」を参照してください。

1 Oracleオブジェクトの概要

この章では、Oracleオブジェクト・リレーショナル・モデルの主な機能および利点について説明します。内容は次のとおりです。

- Oracleオブジェクトの概要

- オブジェクトの利点

- オブジェクト・リレーショナル・モデルの主な機能

Oracleオブジェクトの概要

Oracleオブジェクト型は、データベース内のオブジェクトとして実社会のエンティティ(顧客や発注書など)をモデル化できるようにするユーザー定義型です。

新しいオブジェクト型は、任意の組込みデータベース型、作成済のオブジェクト型、オブジェクト参照およびコレクション型から作成できます。オブジェクト・データ型は、イメージ、音声および動画などの複雑なデータを扱うことができます。Oracle Databaseでは、ユーザー定義のメタデータが、SQL、PL/SQL、Javaおよび他の言語で使用できるスキーマに格納されます。

VARRAYやネストした表などのオブジェクト型および関連オブジェクト指向機能は、データベース内のデータを編成し、アクセスするための高度な手段となります。オブジェクト層の下では、データは従来どおり列や表に格納されますが、このデータは、データに意味を持たせる実社会のエンティティとして扱えます。データベースへ問い合せる場合は、顧客や発注書など、作成したエンティティを選択するだけでよく、列と表に置き換えて考える必要はありません。

従来どおり、データの大部分を相関的に扱いながら、オブジェクト指向機能を利用する方向に進むことも、すべてオブジェクト指向アプローチを使用することもできます。

オブジェクト型は、ユーザー定義型またはADTとも呼ばれます。『Oracle Database PL/SQL言語リファレンス』では、通常ADTといいます。

オブジェクト・リレーショナル形式で格納されているデータは、エディショニング・ビューと互換性がありません。

オブジェクトの利点

一般的に、オブジェクト型モデルは、C++およびJavaで使用されているクラス・メカニズムに似ています。クラスの場合と同様、オブジェクトを再利用できるため、データベース・アプリケーションを短期間で効率的に開発できます。データベースのオブジェクト型をネイティブ・サポートしているため、アプリケーション開発者は自身のアプリケーションで使用するデータ構造に直接アクセスできます。

純粋なリレーショナル・アプローチにより得られるオブジェクトの利点には、次のようなものもあります。

- オブジェクトによる操作とデータのカプセル化

- オブジェクトによる効果

- オブジェクトによる部分対全体の関連の表現

オブジェクトによる操作とデータのカプセル化

データベース表には、データのみが存在します。データに対して実行する可能性のある操作を実行する機能を、オブジェクトに組み込むことができます。したがって、発注情報オブジェクトに、購入品目すべてのコストを計算するメソッドを組み込むことができます。または、顧客オブジェクトに、顧客の購買履歴および支払パターンを戻すメソッドを持たせることもできます。アプリケーションは、メソッドをコールするのみで、情報を取り出せます。

オブジェクトによる効果

オブジェクト型を使用することで、次のような効果があります。

- オブジェクト型およびオブジェクト・メソッドは、データと一緒にデータベースに格納されるため、どのアプリケーションでも利用できるようになります。開発者は、アプリケーションごとに同様の構造およびメソッドを再作成する必要がありません。また、複数の開発者が一貫した標準を使用することになります。

- 一連の関連オブジェクトを1つの単位としてフェッチし、処理できます。サーバーからオブジェクトをフェッチする要求を1回出すのみで、関連付けられた他のオブジェクトが取り出せます。SQLオブジェクト型の列を参照すると、オブジェクト全体が取り出せます。

オブジェクトによる部分対全体の関連の表現

オブジェクト型を使用すると、部分対全体の関連を表現できます。たとえば、在庫品目のリレーショナル表では、ピストンとエンジンに同じステータスが与えられてしまいます。オブジェクトを使用すれば、主キーと外部キーの関連を使用した複数の表で構成される複雑なスキーマを使用して、ピストンをエンジンのパーツとして表現する必要がありません。オブジェクトは他のオブジェクトを属性として持ち、属性オブジェクトは個別のオブジェクト属性も持てます。オブジェクト型を結合することにより、この方法でパーツリスト全体の階層を作成できます。

オブジェクト・リレーショナル・モデルの主な機能

Oracle Databaseでは、オブジェクト型モデルはリレーショナル・モデルの拡張機能として実装されますが、高速コミット、バックアップとリカバリ、スケーラブルな接続性、行レベルのロック、読取り一貫性など、標準のリレーショナル・データベース機能は引き続きサポートされます。

SQLや各種のプログラム・インタフェースおよび言語(PL/SQL、Java、Oracle Call Interface、Pro*C/C++、OO4OおよびC#など)には、Oracleオブジェクトをサポートするための拡張機能が追加されています。その結果、リレーショナル・データベースの優れた並行性とスループットを保つと同時に、オブジェクト・インタフェースの直観性と経済性を実現する、オブジェクト・リレーショナル・モデルが誕生しました。

この項の内容は次のとおりです。

- Oracleオブジェクトのデータベース機能

- Oracleオブジェクトの言語にバインドされた機能

Oracleオブジェクトのデータベース機能

この項では、データベースに関連のあるオブジェクト・リレーショナル・モデルの機能と概念を説明します。

この項の内容は次のとおりです。

- オブジェクト型について

- オブジェクト・インスタンスについて

- オブジェクト・メソッドについて

- オブジェクトを表に格納する方法

- オブジェクト識別子による行オブジェクトの識別

- 行オブジェクトの参照の使用

- Oracleコレクションの使用

- オブジェクト・ビューによるリレーショナル・データへのアクセス

- 型継承の使用

- 型進化による既存のオブジェクト型の変更

オブジェクト型について

オブジェクト型はある種のデータ型です。NUMBERやVARCHAR2のような標準的なデータ型の場合と同じ方法で使用できます。たとえば、オブジェクト型をリレーショナル表の列のデータ型として指定し、オブジェクト型の変数を宣言できます。値は、その型の変数またはインスタンスです。オブジェクト・インスタンスは、オブジェクトとも呼ばれます。

図1-1に、オブジェクト型person_typとオブジェクト型の2つのインスタンスを示します。

図1-1 オブジェクト型とオブジェクト・インスタンス

オブジェクト型は、構造と動作の両方を定義する見取り図またはテンプレートとして機能します。オブジェクト型はデータベース・スキーマ・オブジェクトで、他のスキーマ・オブジェクトと同様に管理制御されます。アプリケーション・コードは、これらのオブジェクトを取得および操作できます。第7章「Oracleオブジェクトの管理」を参照してください。

オブジェクト型を定義するには、CREATE TYPE文を使用します。

例1-1に、person_typというオブジェクト型の作成方法を示します。この例では、オブジェクト仕様部とオブジェクト本体が定義されています。SQL文CREATE TYPEおよびSQL文CREATE TYPE BODYの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

注意:
例の実行: このガイドの例の多くは、HRサンプル・スキーマを使用して実行できます。ほとんどの例には、前の例のコードが必要かどうかを示すコメントが最初に記されています。
サンプル・スキーマの作成方法および使用方法の詳細は、『Oracle Databaseサンプル・スキーマ』を参照してください。

例1-1 person_typオブジェクト型の作成

CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
first_name     VARCHAR2(20),
last_name      VARCHAR2(25),
email          VARCHAR2(25),
phone          VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ));
/

CREATE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) IS
BEGIN
-- use the PUT_LINE procedure of the DBMS_OUTPUT package to display details
DBMS_OUTPUT.PUT_LINE(TO_CHAR(idno) || ' ' || first_name || ' ' || last_name);
DBMS_OUTPUT.PUT_LINE(email || ' '  || phone);
END;
END;
/

オブジェクト型は、リレーショナル・データベースに固有の標準的なデータ型とは異なります。

- Oracle Databaseでは、事前定義のオブジェクト型は提供されません。例1-1に示したように、オブジェクト型は、ユーザー定義型と組込み型を組み合せて定義します。

- オブジェクト型は、図1-2に示すように属性およびメソッドで構成されます。

- 属性は、オブジェクトに関するデータを保持します。属性は宣言されたデータ型を持ち、このデータ型が別のオブジェクト型になることもあります。

- メソッドは、アプリケーションがオブジェクト型の属性に対して操作を実行するために使用できるプロシージャまたはファンクションです。メソッドはオプションです。メソッドは、その型のオブジェクトの動作を定義します。

図1-2 オブジェクトの属性およびメソッド

オブジェクト・インスタンスについて

オブジェクト型の変数は、その型のインスタンス、すなわちオブジェクトです。オブジェクトは、その型に定義された属性およびメソッドを持ちます。オブジェクト・インスタンスは具体的な存在なので、値をその属性に割り当て、そのメソッドをコールできます。

オブジェクト型を定義しても、記憶域は割り当てられません。オブジェクト型を定義すると、SQL文のNUMBERやVARCHAR2のような型を使用する場所のほとんどでそのオブジェクト型を使用できるようになります。オブジェクト型のインスタンスを作成すると、記憶域が割り当てられます。

例1-2に、例1-1で作成したperson_typのオブジェクト・インスタンスを作成する方法と、これらのインスタンスを連絡先として記録するためのリレーショナル表を定義する方法を示します。

例1-2 オブジェクト型の列を持つcontacts表の作成

-- requires existing person_typ fr. Ex 1-1
CREATE TABLE contacts (
contact         person_typ,
contact_date    DATE );

INSERT INTO contacts VALUES (
person_typ (65, 'Verna', 'Mills', 'vmills@example.com', '1-650-555-0125'),
'24 Jun 2003' );

contacts表は、オブジェクト型をそのcontact列のデータ型として持つリレーショナル表です。リレーショナル表の列を占有するオブジェクトを、列オブジェクトといいます。「オブジェクトを表に格納する方法」を参照してください。

オブジェクト・メソッドについて

オブジェクト・メソッドとは、定義された型のオブジェクトに実行させる動作を実装する目的で、オブジェクト型定義に宣言できるファンクションまたはプロシージャのことです。

型定義には、一般的に、次のようなメソッドを宣言できます。

- メンバー・メソッド
メンバー・メソッドを使用すると、オブジェクトのデータへのアクセスを提供することも、アプリケーションがデータに対して実行する操作を定義することもできます。アプリケーションは、オブジェクトに対応するメソッドをコールして、操作を実行します。

- 静的メソッド
静的メソッドは、オブジェクト・インスタンスを比較し、特定のオブジェクトのデータを使用しないオブジェクト型に対してグローバルな操作を実行します。

- コンストラクタ・メソッド
どのオブジェクト型についても、デフォルトのコンストラクタ・メソッドが暗黙的に定義されています(ユーザー定義コンストラクタによって上書きされた場合を除く)。型のオブジェクト・インスタンスを作成するときに、その型のコンストラクタ・メソッドがコールされます。

例1-3では、例1-1で作成したget_idno()メソッドを使用して、contacts表に個人のID番号を表示します。

例1-3 get_idnoオブジェクト・メソッドの使用

-- requires Ex 1-1 and Ex 1-2
SELECT c.contact.get_idno() FROM contacts c;

関連項目:
詳細は、「オブジェクト・メソッド」を参照してください。

オブジェクトを表に格納する方法

オブジェクトは次の2種類の表に格納できます。

- オブジェクト表: オブジェクトのみが格納されます。
オブジェクト表では、それぞれの行が行オブジェクトと呼ばれる1つのオブジェクトを表します。「オブジェクト表の作成および使用」を参照してください。

- リレーショナル表: オブジェクトと他の表データが格納されます。
リレーショナル表の列として格納されたオブジェクト、または他のオブジェクトの属性であるオブジェクトは、列オブジェクトと呼ばれます。例1-2は、person_typオブジェクトのインスタンスを格納するcontacts表を示しています。

包含しているリレーショナル・データベースの外で意味を持つオブジェクト、または複数のリレーショナル・データベース・オブジェクトの間で共有されるオブジェクトは、行オブジェクトとして参照できるようにする必要があります。つまり、そのようなオブジェクトは、リレーショナル表の列に格納するのではなく、行オブジェクトとしてオブジェクト表に格納する必要があります。

関連項目:
「列または行としてのオブジェクトの格納」

オブジェクト表の作成および使用

例1-4に、person_typオブジェクトのオブジェクト表を作成するCREATE TABLE文を示します。

例1-4 person_obj_tableオブジェクト表の作成

-- requires Ex. 1-1
CREATE TABLE person_obj_table OF person_typ;

この表は、次の2つの方法で表示できます。

- 各行にperson_typオブジェクトが入っている単一列表として表示します。ここでは、オブジェクト指向操作が実行できます。

- オブジェクト型person_typの各属性(idno、first_name、last_nameなど)が列を占有している複数列表として表示します。ここでは、リレーショナル操作を実行できます。

例1-5に、オブジェクト表に対する複数の操作を示します。

例1-5 person_obj_tableオブジェクト表に対する操作

-- requires Ex. 1-1 and 1-4
INSERT INTO person_obj_table VALUES (
person_typ(101, 'John', 'Smith', 'jsmith@example.com', '1-650-555-0135') );

SELECT VALUE(p) FROM person_obj_table p
WHERE p.last_name = 'Smith';

DECLARE
person person_typ;
BEGIN -- PL/SQL block for selecting a person and displaying details
SELECT VALUE(p) INTO person FROM person_obj_table p WHERE p.idno = 101;
person.display_details();
END;
/

例1-5のSQL文INSERT INTOは、person_typオブジェクトをperson_obj_tableに挿入し、person_obj_tableを複数列表として扱います。

SQL文SELECTでは、VALUEファンクションを使用して、person_obj_tableから単一列表として抽出し、行をオブジェクト・インスタンスとして戻します。VALUEファンクションの詳細は、「VALUE」を参照してください。

PL/SQLブロックでは、特定の個人が選択され、person_typのメンバー・ファンクションが実行されて、指定の個人に関する詳細が表示されます。PL/SQLのオブジェクトへの使用の詳細は、第3章『PL/SQLのオブジェクト型への使用』を参照してください。

オブジェクト識別子による行オブジェクトの識別

オブジェクト識別子(OID)は、オブジェクト表の行オブジェクトを一意に識別します。オブジェクト識別子に直接アクセスすることはできませんが、「行オブジェクトの参照の使用」で説明するように、オブジェクト識別子の参照(REF)を作成してREFに直接アクセスすることはできます。

2種類のオブジェクト識別子があります。

- システム生成のオブジェクト識別子(デフォルト)
主キー・ベースのオプションを選択しないかぎり、オブジェクト表の行オブジェクトには、システム生成のオブジェクト識別子が自動的に作成されます。

- 主キー・ベースのオブジェクト識別子
CREATE TABLE文を使用して表を作成するときに、主キー・ベースのOIDを作成することを選択できます。

注意:
列オブジェクトは行の主キーで識別されるため、特定のオブジェクト識別子は必要ありません。

関連項目:

- 「オブジェクト・ビューに対するオブジェクト識別子の指定」

- 「オブジェクト識別子(OID)の記憶域上の考慮点」

- 「オブジェクト識別子および参照」

行オブジェクトの参照の使用

REFとは、オブジェクト識別子(OID)から作成できる行オブジェクトへの論理ポインタまたは参照のことです。REFを使用すると、オブジェクトを取得、調査または更新できます。同じオブジェクト型階層の異なるオブジェクトを指すようにREFを変更したり、REFにNULL値を割り当てることも可能です。

REFは、Oracle Databaseの組込みデータ型です。REFとREFのコレクションではオブジェクト間の関連付け(特に多対1リレーションシップ)がモデル化されるため、外部キーの必要性が減少します。REFは、オブジェクト間をナビゲートする簡単なメカニズムを提供します。

例1-6に、REFの単純な使用方法を示します。

例1-6 emp_person_typオブジェクトへのREFの使用

CREATE TYPE emp_person_typ AS OBJECT (
name     VARCHAR2(30),
manager  REF emp_person_typ );
/
CREATE TABLE emp_person_obj_table OF emp_person_typ;

INSERT INTO emp_person_obj_table VALUES (
emp_person_typ ('John Smith', NULL));

INSERT INTO emp_person_obj_table
SELECT emp_person_typ ('Bob Jones', REF(e))
FROM emp_person_obj_table e
WHERE e.name = 'John Smith';

この例では最初に、上司としてNULL値を使用してJohn Smithというemp_person_typを作成しています。次に、Bob Jonesというemp_person_typをJohn Smithの部下として追加しています。

次の問合せおよびその出力に結果を示します。

COLUMN name FORMAT A10
COLUMN manager FORMAT A50
select * from emp_person_obj_table e;

NAME MANAGER
---------- --------------------------------------------------
John Smith
Bob Jones 0000220208424E801067C2EABBE040578CE70A0707424E8010
67C1EABBE040578CE70A0707
例1-10に、Managerがオブジェクト識別子ではなく名前で表示されるように、オブジェクトを参照解除する方法を示します。

「REF型の列および属性のルール」および「REFの設計上の考慮点」を参照してください。

有効範囲付きREFの使用

指定したオブジェクト表を参照するように列型、コレクション要素またはオブジェクト型属性を制限するには、REFを宣言するときにSQL制約副次句SCOPE ISを使用します。有効範囲付きREFでは、有効範囲指定なしのREFに比べて、少ない記憶域でより効率的なアクセスが可能です。

例1-7は、有効範囲がperson_typ型のオブジェクト表であるperson_obj_tableに制限されている、REF列のcontact_refを示しています。

例1-7 有効範囲付きREFを使用したcontacts_ref表の作成

-- requires Ex. 1-1, 1-4, and 1-5
CREATE TABLE contacts_ref (
contact_ref   REF person_typ SCOPE IS person_obj_table,
contact_date  DATE );

表に行を挿入するには、次のコマンドを発行します。

INSERT INTO contacts_ref
SELECT REF(p), '26 Jun 2003'
FROM person_obj_table p
WHERE p.idno = 101;

REFの有効範囲は、宣言された型のオブジェクト表(この例では、person_typ)または宣言された型の任意のサブタイプのオブジェクト表に制限できます。REFの有効範囲がサブタイプのオブジェクト表に制限されている場合、表内のサブタイプ(およびそのサブタイプ)のインスタンスの参照のみを含むように、REF列が効果的に制限されます。「SQLオブジェクト型の継承」を参照してください。

参照先がないREFのチェック

オブジェクトが削除されている場合、または必要な権限が削除されている場合、REFにより識別されるオブジェクトが使用できなくなることがあります。これを参照先がないREFといいます。Oracle DatabaseのSQL述語IS DANGLINGを使用すると、REFがこの条件を満たしているかどうかをテストできます。

参照先がないREFは、参照整合性制約を定義することによって回避できます。「REF型の列および属性のルール」を参照してください。

REFの参照解除

REFが参照するオブジェクトにアクセスすることを、REFを参照解除するといいます。Oracle Databaseでは、この参照解除を行うDEREF演算子が提供されています。

例1-8 DEREFを使用したREFの参照解除

-- requires Ex. 1-6
SELECT DEREF(e.manager) FROM emp_person_obj_table e;

DEREF(E.MANAGER)(NAME, MANAGER)
----------------------------------------------------------------
EMP_PERSON_TYP('John Smith', NULL)
例1-9は、参照先がないREFを参照解除するとNULLオブジェクトが戻されることを示しています。

例1-9 参照先がないREFの参照解除

--requires Ex. 1-1, 1-4, 1-5, and 1-7
-- DELETE command needed to cause dangling refDELETE from person_obj_table WHERE idno = 101;/
SELECT DEREF(c.contact_ref), c.contact_date FROM contacts_ref c;

Oracle Databaseでは、REFの暗黙的な参照解除も提供されています。たとえば、特定の従業員の上司の名前にアクセスするには、SELECT文を使用できます。

例1-10では、ポインタを上司の名前から移し、上司の名前e.manager.nameを取り出します。

例1-10 REFの暗黙的な参照解除

-- requires Ex. 1-6
SELECT e.name, e.manager.name FROM emp_person_obj_table e
WHERE e.name = 'Bob Jones';

SQLではこのようにREFに続けることができますが、PL/SQLでは例1-8のようにDEREFキーワードを使用する必要があります。

行オブジェクトへのREFの取得

オブジェクト表からオブジェクトを選択してREF演算子を適用することで、その行オブジェクトに対するREFが取得できます。

例1-11に、idnoが101である個人に対するREFを取得する方法を示します。

例1-11 行オブジェクトへのREFの取得

-- requires Ex. 1-1, 1-4, and 1-5
DECLARE
person_ref REF person_typ;
person person_typ;
BEGIN

SELECT REF(p) INTO person_ref
FROM person_obj_table p
WHERE p.idno = 101;

select deref(person_ref) into person from dual;
person.display_details();

END;
/

問合せは1行のみを戻します。「REFの記憶域サイズ」を参照してください。

REF変数の比較

2つのREF変数の比較ができるのは、これらの変数が参照するターゲットに宣言された型が一致するか、または一方がもう一方のサブタイプの場合のみです。等価比較のみ実行できます。

Oracleコレクションの使用

Oracle Databaseでは、複数値属性および多対多リレーションシップをモデル化するために、VARRAYとネストした表の2つのコレクション・データ型がサポートされます。コレクション型は、他のデータ型が使用されるところであれば、どこでも使用できます。また、コレクション型の列に加え、コレクション型のオブジェクト属性も使用できます。たとえば、発注書オブジェクト型に、発注書についての明細項目のコレクションを格納するためのネストした表属性を持たせることができます。

コレクション型を定義するには、CREATE TYPE . . . AS TABLE OF文を使用します。

例1-12に、コレクションおよびオブジェクト型を定義するCREATE TYPE文を示します。

例1-12 people_typコレクション・データ型の作成

-- requires Ex. 1-1
CREATE TYPE people_typ AS TABLE OF person_typ;
/

CREATE TYPE dept_persons_typ AS OBJECT (
dept_no    CHAR(5),
dept_name  CHAR(20),
dept_mgr   person_typ,
dept_emps  people_typ);
/

この例に関して次の点に注意してください。

- コレクション型people_typは、具体的にはネストした表型です。

- dept_persons_typオブジェクト型は、people_typの属性dept.empsを持ちます。ネストした表dept.empsの各行は、例1-1で定義されたperson_typ型のオブジェクトです。

関連項目:
「コレクション・データ型」

オブジェクト・ビューによるリレーショナル・データへのアクセス

オブジェクト・ビューは、オブジェクト・リレーショナル機能を使用して関連するデータにアクセスする方法です。オブジェクト・ビューを使用すると、基礎となるリレーショナル・スキーマを変更せずに、オブジェクト指向アプリケーションを開発できます。

オブジェクト・ビューに属するオブジェクトには、オブジェクト表の行オブジェクトにアクセスする場合と同じ方法でアクセスできます。Oracle Databaseでは、リレーショナル・スキーマおよび表に格納されたデータからの、ユーザー定義型のマテリアライズド・ビュー・オブジェクトの生成もサポートされています。

オブジェクト・ビューを使用すると、型階層によりもたらされるポリモフィズム(多相性)を活用できます。ポリモフィックな式は、その式の宣言された型またはその型のサブタイプの値をとります。ある型階層の構造の一部または全部をミラー化するオブジェクト・ビューの階層を作成すると、その階層内のすべてのビューに対して問合せを行い、関心のある特化レベルでデータにアクセスできます。サブビューを持つオブジェクト・ビューの問合せを行う場合は、ポリモフィック・データ、すなわちビューの型とそのサブタイプの両方の行を取得できます。第6章「オブジェクト・モデルのリレーショナル・データへの適用」を参照してください。

型継承の使用

型継承を使用すると、型階層を作成できます。型階層とは、スーパータイプと呼ばれる、共通する祖先のオブジェクト型から導出される特化されたサブタイプの連続レベルのセットです。導出サブタイプは、親オブジェクト型の機能を継承すると同時に、親の型定義を拡張できます。特殊な型を使用することで、新しい属性またはメソッドの追加や、親から継承するメソッドの再定義ができます。その結果発生する型階層により、アプリケーション・モデルの複雑さを管理するために必要な高度な抽象化レベルが得られます。たとえば、一般的な個人オブジェクト型から、追加属性またはメソッドを持つ、個人の特殊な型である学生型または定時制の学生型を導出できます。

関連項目:
「SQLオブジェクト型の継承」

図1-3は、Person_tの下に作成されたStudent_tおよびEmployee_tという2つのサブタイプと、Student_tの下に作成された1つのサブタイプPartTimeStudent_tを示しています。

図1-3 型階層

型進化による既存のオブジェクト型の変更

型進化を使用すると、既存のオブジェクト型を(すでに表で使用されていても)変更したり、進化させることができます。型進化はALTER TYPE文によって行われるため、そのオブジェクト型のすべてのインスタンスに変更を伝播できます。

ALTER TYPE文は、CREATE TYPE文と基本的に同じ妥当性チェックを使用して、変更対象の型の依存関係を調べます。型またはその依存型のいずれかについて型の妥当性が確認されない場合は、ALTER TYPE文はロールバックします。

変更された型を使用するすべての表および列のメタデータは、データを新しい形式で格納できるように、新しい型定義に対応して更新されます。既存データを新しい形式に変換する処理は、データ更新時に一括または個別に行えます。いずれの場合も、データが古い型定義の形式のまま格納されていても、データは、必ず新しい型定義で表示されます。

関連項目:

- 「型進化」

- 「型進化に関する考慮点」

Oracleオブジェクトの言語にバインドされた機能

この項では、言語およびApplication Program Interface (API)に関連のあるオブジェクト・リレーショナル・モデルの主要な機能を説明します。

SQLのオブジェクトの拡張

Oracle Databaseでは、オブジェクト関連機能をサポートするために、SQL拡張機能(DDLを含む)を提供し、オブジェクト型の作成、変更または削除、オブジェクト型の表への格納、およびオブジェクト・ビューの作成、変更または削除に対応します。オブジェクト型、参照およびコレクションのサポートには、DMLと問合せ拡張機能が用意されています。「SQLおよびオブジェクト型」を参照してください。

PL/SQLのオブジェクト拡張

PL/SQLでは、オブジェクト型をシームレスに操作できます。したがって、アプリケーション開発者は、PL/SQLを使用して、データベース・サーバー内で実行するユーザー定義型に対してロジックや操作を実装できます。第3章「PL/SQLでのオブジェクト型の使用」を参照してください。

Oracleオブジェクトに対するJavaのサポート

Oracle Java VMはOracle Databaseと密接に統合されており、Java Database Connectivity (JDBC)へのオブジェクト拡張機能を介して行うOracleオブジェクトへのアクセスをサポートします。これにより動的SQLが提供され、また静的SQLを提供するSQLJが提供されます。したがって、アプリケーション開発者は、Javaを使用して、データベース内で実行するオブジェクト型に対してロジックや操作を実装できます。SQL型を既存のJavaクラスにマップして、Javaオブジェクトに永続ストレージを持たせることができます。「Javaオブジェクトの記憶域」を参照してください。

関連項目:
『Oracle Database JDBC開発者ガイドおよびリファレンス』

外部プロシージャ

オブジェクト型のデータベース・ファンクション、プロシージャまたはメンバー・メソッドは、PL/SQL、Java、Cまたは.NETで、外部プロシージャとして実装できます。外部プロシージャは、Cなどの低レベル言語でより高速で簡単にできる作業に最適です。外部プロシージャは常に、データベースのアドレス空間外でセーフ・モードで実行されます。1つ以上のパラメータをシステム定義汎用型として宣言する共通の外部プロシージャが書き込めます。したがって、外部プロシージャはシステム定義の汎用型を使用して、任意の組込み型またはユーザー定義型のデータを扱うことができます。

Object Type Translator/JPublisher

OTTおよびOracle JPublisherは、Oracleデータ・ディクショナリからのスキーマ情報を使用して、Javaクラス、C構造体およびインジケータが入っているヘッダー・ファイルを生成することによって、クライアント側でオブジェクト型スキーマへのマッピングを行います。ホスト言語アプリケーションで、データベース・オブジェクトへ透過的にアクセスするために、生成されたこれらのヘッダー・ファイルを使用できます。

クライアント側キャッシュ

Oracle Databaseでは、データベースに格納された永続オブジェクトに効率的にアクセスするためのオブジェクト・キャッシュが提供されています。オブジェクトのコピーは、オブジェクト・キャッシュに置かれます。一度データがクライアントにキャッシュされると、アプリケーションは、これらのデータに対してメモリー・スピードでアクセスできます。キャッシュ内で行われたオブジェクトの変更は、Oracle Call Interfaceプログラム・インタフェースのオブジェクト拡張機能を使用して、データベースに反映できます。

Oracle Call InterfaceおよびOracle C++ Call Interface

Oracle Call Interface (OCI)およびOracle C++ Call Interfaceは、アプリケーション開発者およびツール開発者向けの包括的なアプリケーション・プログラミング・インタフェースを提供します。Oracle Call Interfaceは、Oracle Databaseに接続する機能と、データベース内のオブジェクトにアクセスするトランザクションを制御する機能を備えたランタイム環境となります。これにより、アプリケーション開発者は、クライアント側のオブジェクト・キャッシュ内のオブジェクトおよびそれらの属性に、ナビゲーショナル・アクセス(相互に関連付けられた複数のオブジェクトを横断)、または結合アクセス(宣言SQL DMLでデータの性質を指定)して操作できます。Oracle Call Interfaceには、データベース内で定義されたオブジェクト型に関するメタデータに実行時にアクセスする様々なファンクションが用意されています。「Oracle Call Interface (OCI)」および「Oracle C++ Call Interface (OCCI)」を参照してください。

Pro*C/C++のオブジェクト拡張

Oracle Pro*C/C++プリコンパイラは、埋込みSQLアプリケーション・プログラミング・インタフェースを備え、Oracle Call Interfaceより高レベルの抽象化を行います。Oracle Call Interfaceと同様に、Pro*C/C++プリコンパイラでも、アプリケーション開発者は、Oracleのクライアント側のオブジェクト・キャッシュおよびObject Type Translatorユーティリティが使用できます。Pro*C/C++は、Oracleオブジェクト型を対象としたCバインド変数の使用をサポートしています。また、Pro*C/C++には、SQL型オブジェクトの割当てや解放を行ったり、SQL DMLまたはナビゲーショナル・インタフェースを使用してこれらのオブジェクトにアクセスするための、単純化された構文が用意されています。「Oracle Call Interface (OCI)」を参照してください。

OO4Oのオブジェクト拡張

Oracle Objects For OLE (OO4O)は、一連のCOMオートメーション・インタフェースおよびオブジェクトで、Oracleデータベース・サーバーに接続し、問合せを実行し、結果を管理します。OO4Oのオートメーション・インタフェースは、Oracle Databaseの機能に簡単かつ効率的にアクセスする手段となります。このインタフェースは、Microsoft COMオートメーション・テクノロジをサポートする、実質的にほとんどのプログラミング言語またはスクリプティング言語で使用できます。これらの言語としては、Visual Basic、Visual C++、ExcelのVBA、VBScriptおよびIIS Active Server PagesのJavaScriptがあります。「Oracle Objects for OLE (OO4O)」を参照してください。

.NETのオブジェクトの拡張

Oracle Developer Tools for Visual Studio (ODT)およびOracle Data Provider for .NET (ODP.NET)は、Oracleのオブジェクト・リレーショナル・データ型、コレクションおよびREFにマップされる.NETカスタム・オブジェクトをサポートしています。ODTは、Visual Studio統合開発環境に組み込まれたツール・セットであり、Oracle Database内部でのこれらのデータ型の管理を可能にします。ODTカスタム・クラス・ウィザードを実行すると、Oracleオブジェクトを.NETカスタム型に自動的にマップでき、Oracle Databaseと.NETアプリケーション間でのデータ共有が容易になります。これらの.NETカスタム型へのデータ・アクセスは、ODP.NETを介して行われます。

関連項目:

- 『Oracle Database Extensions for .NET開発者ガイド』

- 『Oracle Data Provider for .NET開発者ガイド』

- Oracle Developer Tools for Visual Studioヘルプ

2 Oracleオブジェクトの基本コンポーネント

この章では、Oracle SQLオブジェクトを扱ううえでの基本的な情報について説明します。ここでは、オブジェクト型およびサブプログラムについて説明する他、共有ルート型から導出し、継承によって結合するオブジェクト型の階層を作成し扱う方法について説明します。

注意:
例の実行: 第2章の例を実行するためには、第1章で作成したオブジェクトの削除が必要な場合があります。

内容は次のとおりです。

- SQLオブジェクト型および参照

- オブジェクト・メソッド

- SQLオブジェクト型の継承

- オブジェクトに便利なファンクションおよび演算子

SQLオブジェクト型および参照

この項では、次のSQLオブジェクト型および参照について説明します。

- NULLオブジェクトおよび属性

- 文字長セマンティクス

- オブジェクト表の制約

- オブジェクト表の索引

- オブジェクト表のトリガー

- REF型の列および属性のルール

- 名前解決

- リモート・データベースでユーザー定義型を使用する際の制限事項

Oracle SQLオブジェクト型は、CREATE TYPE文で作成します。オブジェクト型の一般的な作成例を例2-1に示します。

関連項目:

- SQL文CREATE TYPEの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- SQL文CREATE TYPE BODYの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

NULLオブジェクトおよび属性

自分自身の値がNULLであるオブジェクトを、アトミックNULLといいます。アトミックNULLオブジェクトは、すべての属性の値がNULL値であるオブジェクトとは異なります。NULL値を持つオブジェクトにおいて、NULLに初期化されているか、またはまったく初期化されていない表列、オブジェクト属性、コレクションまたはコレクション要素はNULLである可能性があります。通常、NULL値は、後で実際の値で置き換えられます。すべての属性がNULLの場合でも、これらの属性を変更し、オブジェクトのサブプログラムまたはメソッドをコールできます。ただし、アトミックNULLオブジェクトの場合は、これらの処理はできません。

例2-1では、contacts表を作成し、person_typオブジェクト型とこの型の2つのインスタンスを定義します。

例2-1 表のオブジェクトに対するNULLの挿入

CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) );
/

CREATE OR REPLACE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) IS
BEGIN
-- use the PUT_LINE procedure of the DBMS_OUTPUT package to display details
DBMS_OUTPUT.PUT_LINE(TO_CHAR(idno) || ' - '  || name || ' - '  || phone);
END;
END;
/
CREATE TABLE contacts (
contact        person_typ,
contact_date   DATE );

INSERT INTO contacts VALUES (
person_typ (NULL, NULL, NULL), '24 Jun 2003' );

INSERT INTO contacts VALUES (
NULL, '24 Jun 2003' );

person_typの2つのインスタンスが表に挿入され、異なる2つの結果が生成されます。どちらの場合も、Oracle Databaseがcontacts表に新しい行用の領域を割り当て、DATE列を指定された値に設定します。ただし、最初の文は、オブジェクト用の領域をcontact列に割り当て、そのオブジェクトの各属性にNULLを設定します。2番目の文は、person_typフィールドそのものをNULLに設定しますが、オブジェクト用の領域は割り当てません。

NULL値のチェックは省略できる場合があります。リレーショナル表の行または行オブジェクト自体は、NULLに初期化できません。オブジェクトのネストした表には、値がNULLである要素を含められません。

ネストした表または配列はNULLになる可能性があるため、その状態を処理する必要があります。NULLコレクションと何も要素を持たない空のコレクションは異なります。

関連項目:
「PL/SQLでの未初期化オブジェクトの処理規則」

文字長セマンティクス

一部の文字が複数のバイトで構成される場合でも、オブジェクト属性およびコレクション内で、キャラクタ・タイプCHARおよびVARCHAR2の長さをバイトではなく文字数で指定できます。

CHARおよびVARCHAR2属性の文字単位の長さを指定するには、長さの仕様に修飾子charを追加します。

CHARおよびVARCHAR2と同様、NCHARおよびNVARCHAR2も、オブジェクトおよびコレクション内で属性型として使用できます。NCHARおよびNVARCHAR2は、常に暗黙的に文字数で測定されるため、char修飾子は使用しません。

たとえば、次の文により、文字長VARCHAR2属性およびNCHAR属性の両方を持つオブジェクトが作成されます。

例2-2 char修飾子を使用したemployee_typオブジェクトの作成

CREATE OR REPLACE TYPE employee_typ AS OBJECT (
name        VARCHAR2(30 char),
language    NCHAR(10),
phone       VARCHAR2(20) );
/

char修飾子を使用せずに長さが指定されたCHARおよびVARCHAR2属性の場合、NLS_LENGTH_SEMANTICS初期化パラメータ設定(CHARまたはBYTE)はデフォルトの測定単位を示します。

関連項目:
文字長セマンティクスの詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

オブジェクト表の制約

他の表と同様に、オブジェクト表にも制約を定義できます。参照範囲が制限されていないREF以外の列オブジェクトのリーフ・レベル・スカラー属性に対して、制約を定義できます。

次の各例に制約の定義を示します。

例2-3では、オブジェクト表office_tabのoffice_id列に暗黙的なPRIMARY KEY制約を定義します。

例2-3 制約を使用したoffice_tabオブジェクト表の作成

-- requires Ex. 2-1
CREATE OR REPLACE TYPE location_typ AS OBJECT (
building_no  NUMBER,
city         VARCHAR2(40) );
/

CREATE OR REPLACE TYPE office_typ AS OBJECT (
office_id    VARCHAR(10),
office_loc   location_typ,
occupant     person_typ );/

CREATE TABLE office_tab OF office_typ (
office_id      PRIMARY KEY );

例2-3で定義されているオブジェクト型location_typは、例2-4のdepartment_mgrs表のdept_loc列の型です。

例2-4では、表のlocation_typオブジェクトのスカラー属性に制約を定義します。

例2-4 複数の制約を使用したdepartment_mgrs表の作成

-- requires Ex. 2-1 and 2-3
CREATE TABLE department_mgrs (
dept_no     NUMBER PRIMARY KEY,
dept_name   CHAR(20),
dept_mgr    person_typ,
dept_loc    location_typ,
CONSTRAINT  dept_loc_cons1
UNIQUE (dept_loc.building_no, dept_loc.city),
CONSTRAINT  dept_loc_cons2
CHECK (dept_loc.city IS NOT NULL) );

INSERT INTO department_mgrs VALUES
( 101, 'Physical Sciences',
person_typ(65,'Vrinda Mills', '1-1-650-555-0125'),
location_typ(300, 'Palo Alto'));

関連項目:
「オブジェクトに対する制約」

オブジェクト表の索引

オブジェクト表およびネストした表の記憶表の列や属性についても、他の表と同様に、索引を定義できます。ネストした表の索引の例は、例5-5を参照してください。

例2-5に示すように、列オブジェクトのリーフ・レベル・スカラー属性に索引を定義できます。有効範囲付きREFの場合、REF型の列または属性にのみ索引を定義できます。この例では、列オブジェクトdept_addrのリーフ・レベル・スカラー属性であるcityに索引を作成します。

例2-5 表のオブジェクト型の索引の作成

-- requires Ex. 2-1, 2-3,
CREATE TABLE department_loc (
dept_no     NUMBER PRIMARY KEY,
dept_name   CHAR(20),
dept_addr   location_typ );

CREATE INDEX  i_dept_addr1
ON  department_loc (dept_addr.city);

INSERT INTO department_loc VALUES
( 101, 'Physical Sciences',
location_typ(300, 'Palo Alto'));
INSERT INTO department_loc VALUES
( 104, 'Life Sciences',
location_typ(400, 'Menlo Park'));
INSERT INTO department_loc VALUES
( 103, 'Biological Sciences',
location_typ(500, 'Redwood Shores'));

Oracle Databaseが索引定義で列名を指定するところには、列オブジェクトのスカラー属性も指定できます。

オブジェクト表のトリガー

オブジェクト表には、他の表と同様に、トリガーを定義できます。ネストした表の記憶表の列または属性に、トリガーは指定できません。トリガー本体でLOB値の変更はできません。トリガーをオブジェクト型とともに使用する場合の制限は他にはありません。

例2-6では、「オブジェクト表の制約」で定義したoffice_tab表にトリガーを定義します。

例2-6 表のオブジェクトのトリガーの作成

-- requires Ex. 2-1 and 2-3
CREATE TABLE movement (
idno           NUMBER,
old_office     location_typ,
new_office     location_typ );

CREATE TRIGGER trigger1
BEFORE UPDATE
OF  office_loc
ON  office_tab
FOR EACH ROW
WHEN  (new.office_loc.city = 'Redwood Shores')
BEGIN
IF :new.office_loc.building_no = 600 THEN
INSERT INTO movement (idno, old_office, new_office)
VALUES (:old.occupant.idno, :old.office_loc, :new.office_loc);
END IF;
END;/
INSERT INTO office_tab VALUES
('BE32', location_typ(300, 'Palo Alto' ),person_typ(280, 'John Chan',
'415-555-0101'));

UPDATE office_tab set office_loc =location_typ(600, 'Redwood Shores')
where office_id = 'BE32';

select * from office_tab;

select * from movement;

関連項目:
「変更および妥当性チェックを制御するINSTEAD OFトリガーの使用」

REF型の列および属性のルール

Oracle Databaseでは、SCOPE句または参照制約句を使用して、REF型の列または属性を制約なしまたは制約付きにすることが可能です。制約なしのREF列には、対応するオブジェクト型のオブジェクト表に含まれている行オブジェクトに対するオブジェクト参照を格納できます。

Oracle Databaseは、そのような列に格納されたオブジェクト参照が、有効な既存の行オブジェクトを指すことを保証しません。したがって、REF列に、既存の行オブジェクトを指していないオブジェクト参照が含まれることがあります。このようなREF値は、参照先がない参照と呼ばれます。

SCOPE制約は、特定のオブジェクト表に適用できます。SCOPE制約が付いた列に格納されたすべてのREF値は、SCOPE句で指定された表の行オブジェクトを指します。ただし、REF値には参照先がない場合があります。

REF列には、外部キーの指定に類似したREFERENTIAL制約を指定することもできます。参照制約のルールは、そのような列に適用されます。つまり、このような列に格納されたオブジェクト参照は、指定されたオブジェクト表内の有効な既存の行オブジェクトを指す必要があります。

REF列には、PRIMARY KEY制約を指定できません。ただし、NOT NULL制約は指定できます。

関連項目:

- 「行オブジェクトの参照の使用」

- 「REF列および属性の代入」

名前解決

Oracle SQLでは、いくつかのリレーショナル操作で表の修飾名を省略できます。たとえば、dept_addrがdepartment_loc表の列で、old_officeがmovement表の列の場合、次の文を使用できます。

SELECT * FROM department_loc WHERE EXISTS
(SELECT * FROM movement WHERE dept_addr = old_office);

Oracle Databaseにより、各列がどの表に属しているかが判断されます。

簡単にメンテナンスできるように、ドット表記法を使用して、表名または表別名で列名を修飾することもできます。次に例を示します。

例2-7 名前解決へのドット表記法の使用

-- requires Ex. 2-1, 2-3, 2-5, and 2-6
SELECT * FROM department_loc WHERE EXISTS
(SELECT * FROM movement WHERE department_loc.dept_addr = movement.old_office);

SELECT * FROM department_loc d WHERE EXISTS
(SELECT * FROM movement m WHERE d.dept_addr = m.old_office);

オブジェクト・リレーショナル機能で表別名を指定する必要がある場合もあります。

表別名が必要な場合

修飾されていない名前を使用すると、問題が発生する場合があります。たとえば、deptsにassignment列を追加した後、問合せの変更をしなかった場合、内側のSELECTがdepts表のassignment列を使用するように、問合せが自動的に再コンパイルされます。この状況を内部取得といいます。

内部取得および参照解決で発生する同様の問題を回避するために、表別名を使用して、サブプログラムまたはオブジェクトの属性へのドット表記による参照を修飾してください。

ドット表記法を使用せずに、オブジェクト表の最上位属性を直接参照する場合は、表別名は任意で使用してください。たとえば、次の文は、person_typオブジェクト型が含まれている2つの表を定義します。person_obj_tableはperson_typ型のオブジェクトのオブジェクト表で、contactsはオブジェクトperson_typの列が格納されているリレーショナル表です。

次の問合せには、idno属性を参照する正しい方法と、誤った方法が示されています。

注意:
これらの文は、この章の他の例とは関連していません。

#1 SELECT idno FROM person_obj_table; --Correct

#2 SELECT contact.idno FROM contacts; --Illegal
#3 SELECT contacts.contact.idno FROM contacts; --Illegal
#4 SELECT p.contact.idno FROM contacts p; --Correct

- #1では、idnoはperson_obj_tableの列の名前です。ドット表記法を使用せずに、この最上位属性を直接参照するので、表別名は不要です。

- #2では、idnoは、contactという名前の列にあるperson_typオブジェクトの属性の名前です。この参照はドット表記法を使用しているので、#4に示すように表別名が必要です。

- #3では、表名そのものを使用して参照を修飾しています。これは不適切なため、表別名を使用する必要があります。

オブジェクト属性またはサブプログラムの参照は、表名がスキーマ名によって修飾される場合でも、表名ではなく表別名を使用して修飾する必要があります。

たとえば、次の式はHRスキーマ、department_loc表、dept_addr列およびこの列のcity属性を参照していますが、これは不適切です。department_locは表名で表別名ではないため、正しい式ではありません。

HR.department_loc.dept_addr.city

REFを使用する属性参照にも同じ要件が適用されます。

表別名は、問合せ全体を通して同じ表を抽出するように要求されます。また、問合せで表示されるスキーマ名と異なる名前である必要があります。

注意:
列にオブジェクト型が含まれているかどうかにかかわらず、すべてのUPDATE文、DELETE文、SELECT文および副問合せに表別名を定義し、それらを使用して列参照を修飾することをお薦めします。

リモート・データベースでユーザー定義型を使用する際の制限事項

現在、オブジェクトまたはユーザー定義型(特に、PL/SQLパッケージ内部で宣言する型とは対照的な、SQL CREATE TYPE文を使用して宣言する型)は、1つのデータベース内部のみで有効です。Oracle Databaseでは、データベース・リンクの使用に次のような制限があります。

- リモート・データベースに接続して、リモート表に対してユーザー定義型またはオブジェクトREFの選択、挿入または更新を行うことはできません。
CREATE TYPE文でオプションのキーワードOIDを使用して、ユーザーが指定したオブジェクト識別子(OID)を作成し、オブジェクト型を複数のデータベースで使用できます。『Oracle Databaseデータ・カートリッジ開発者ガイド』の、オブジェクト型へのOIDの割当てに関する説明を参照してください。

- PL/SQLコード内部でデータベース・リンクを使用して、リモート・ユーザー定義型のローカル変数を宣言することはできません。

- PL/SQLリモート・プロシージャ・コールでユーザー定義型引数を送ったり、値を戻すことはできません。

オブジェクト・メソッド

オブジェクト・メソッドとは、定義された型のオブジェクトに実行させる動作を実装する目的で、オブジェクト型定義に宣言できるファンクションまたはプロシージャのことで、サブプログラムとも呼ばれます。アプリケーションは、サブプログラムをコールし、動作を起動します。

サブプログラムは、PL/SQLまたは他のほとんどすべてのプログラミング言語で書くことができます。PL/SQLまたはJavaで書かれたメソッドは、データベースに格納されます。Cのような他の言語で書かれたメソッドは、外部に格納されます。

注意:
SQLでは、引数を持たないサブプログラム・コールについても、すべてカッコを付ける必要があります。これはPL/SQLには適用されません。

この項では、メソッドの宣言に重点を置いて説明します。PL/SQLでのメソッド起動の詳細は、「オブジェクトのコンストラクタとメソッドに対するコール」を参照してください。

この項では、次のメソッドについて説明します。

- メンバー・メソッド

- 静的メソッド

- コンストラクタ・メソッド

- 外部実装メソッド

メンバー・メソッド

メンバー・メソッドにより、アプリケーションはオブジェクト・インスタンスのデータにアクセスできます。オブジェクト型のオブジェクトに実行させるそれぞれの操作について、メンバー・メソッドをオブジェクト型に定義します。比較メソッドでないメンバー・メソッドは、MEMBER FUNCTIONまたはMEMBER PROCEDUREとして定義します。比較メソッドでは、「オブジェクトを比較するためのメンバー・メソッド」で説明するように、MAP MEMBER FUNCTIONまたはORDER MEMBER FUNCTIONを使用します。

たとえば、メンバー・メソッドでは、発注書の明細項目の合計コストを計算するファンクションget_sum()を宣言できます。次のコード行は、発注書poのファンクションをコールし、金額をsum_line_itemsの中に入れて戻します。

sum_line_items:= po.get_sum();

ドット表記により、現在のオブジェクトと、そのオブジェクトがコールするメソッドを指定します。パラメータがない場合でも、カッコは必要です。

この項の内容は次のとおりです。

- メンバー・メソッド内のSELFパラメータ

- オブジェクトを比較するためのメンバー・メソッド

メンバー・メソッド内のSELFパラメータ

メンバー・メソッドは、現在メソッドを起動しているオブジェクト・インスタンスを示すSELFと呼ばれる組込みパラメータを持ちます。

SELFは明示的に宣言できますが、必ずしもそうする必要はありません。SELF修飾子を使用せずに暗黙的にSELFの属性とメソッドを参照するメンバー・メソッドを記述するほうが簡単です。例2-8のコードおよびコメントは、属性hgt、lenおよびwthを修飾せずに、暗黙的なSELFパラメータを使用するメソッド起動を示しています。

例2-8 メンバー・メソッドの作成

-- Ex. 2-8 Creating a Member Method
CREATE OR REPLACE TYPE solid_typ AS OBJECT (
len    INTEGER,
wth    INTEGER,
hgt    INTEGER,
MEMBER FUNCTION surface RETURN INTEGER,
MEMBER FUNCTION volume RETURN INTEGER,
MEMBER PROCEDURE display (SELF IN OUT NOCOPY solid_typ) );
/

CREATE OR REPLACE TYPE BODY solid_typ AS
MEMBER FUNCTION volume RETURN INTEGER IS
BEGIN
RETURN len * wth * hgt;
-- RETURN SELF.len * SELF.wth * SELF.hgt; -- equivalent to previous line
END;
MEMBER FUNCTION surface RETURN INTEGER IS
BEGIN -- not necessary to include SELF in following line
RETURN 2 * (len * wth + len * hgt + wth * hgt);
END;
MEMBER PROCEDURE display (SELF IN OUT NOCOPY solid_typ) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Length: ' || len || ' - '  || 'Width: ' || wth
|| ' - '  || 'Height: ' || hgt);
DBMS_OUTPUT.PUT_LINE('Volume: ' || volume || ' - ' || 'Surface area: '
|| surface);
END;
END;
/

CREATE TABLE solids of solid_typ;
INSERT INTO solids VALUES(10, 10, 10);
INSERT INTO solids VALUES(3, 4, 5);
SELECT * FROM solids;
SELECT s.volume(), s.surface() FROM solids s WHERE s.len = 10;
DECLARE
solid solid_typ;
BEGIN -- PL/SQL block for selecting a solid and displaying details
SELECT VALUE(s) INTO solid FROM solids s WHERE s.len = 10;
solid.display();
END;
/

SELFは、常にメソッドに最初に渡されるパラメータです。

- メンバー・ファンクションにSELFが宣言されていない場合、そのパラメータ・モードはデフォルトでINに設定されます。

- メンバー・プロシージャにSELFが宣言されていない場合、そのパラメータ・モードはデフォルトでIN OUTに設定されます。デフォルトの動作には、NOCOPYコンパイラ・ヒントは含まれません。

「メンバー・プロシージャでのSELF IN OUT NOCOPYの使用」も参照してください。

オブジェクトを比較するためのメンバー・メソッド

オブジェクト型の変数を比較し、順序付けをするには、これらの変数を比較する基準を指定する必要があります。CHARまたはREALのようなスカラー・データ型の値には、事前定義された順序が存在するため、これらの値は比較できます。ただし、各種のデータ型の属性を多数持つ可能性のあるperson_typのようなオブジェクト型には、事前定義された比較軸は存在しません。オブジェクトを比較する場合、マップ・メソッドかオーダー・メソッドのいずれかを定義できますが、両方を定義することはできません。

マップ・メソッドはオブジェクトの戻り値をスカラー値にマップし、スカラー軸上の位置に従って複数の値を順序付けできます。オーダー・メソッドは特定の2つのオブジェクトの値を直接比較します。

マップ・メソッド

マップ・メソッドは、比較およびソートに使用できる値を戻します。戻り値は、Oracleの組込みデータ型(LOBおよびBFILEを除く)か、CHARACTERやREALなどのANSI SQL型になります。『Oracle Database SQL言語クイック・リファレンス』.の該当する項を参照してください。

一般に、マップ・メソッドは、オブジェクトの属性に対して計算を実行して戻り値を生成します。

マップ・メソッドは自動的にコールされ、obj_1 > obj_2のような比較や、行によるソートを必要とするDISTINCT、GROUP BY、UNIONおよびORDER BY句によって示される比較を評価します。

obj_1およびobj_2がマップ・メソッドmap()を使用して比較できる2つのオブジェクト変数であるとすると、次の比較は、

obj_1 > obj_2

次の比較と同等になります。

obj_1.map() > obj_2.map()

他のリレーショナル演算子についても、比較は同様です。

次の例は、四角形オブジェクトを面積で比較する際の基準を規定するマップ・メソッドarea()を定義しています。

例2-9 マップ・メソッドの作成

CREATE OR REPLACE TYPE rectangle_typ AS OBJECT (
len NUMBER,
wid NUMBER,
MAP MEMBER FUNCTION area RETURN NUMBER);
/

CREATE OR REPLACE TYPE BODY rectangle_typ AS
MAP MEMBER FUNCTION area RETURN NUMBER IS
BEGIN
RETURN len * wid;
END area;
END;
/

例2-10 マップ・メソッドの起動

DECLARE
po rectangle_typ;

BEGIN
po :=NEW rectangle_typ(10,5);

DBMS_OUTPUT.PUT_LINE('AREA:' || po.area()); -- prints AREA:50
END;
/

サブタイプの場合は、そのルート・スーパータイプでマップ・メソッドを宣言している場合にかぎり、マップ・メソッドを宣言できます。

オブジェクト型が含まれているコレクションを比較する際のマップ・メソッドの使用方法は、「等価および非等価比較」を参照してください。

オーダー・メソッド

オーダー・メソッドは、オブジェクトを1対1で直接比較します。マップ・メソッドとは異なり、オーダー・メソッドは多数のオブジェクトの順序を判別できません。オーダー・メソッドは、使用されている基準に基づいて、現在のオブジェクトが比較対象のオブジェクトより小さいか、等しいかまたは大きいかを知らせるのみです。

オーダー・メソッドはオブジェクト(SELF)のファンクションの1つで、宣言されたパラメータ(同じ型のオブジェクト)を1つ持ちます。このメソッドは、負の数、0 (ゼロ)または正の数のいずれかを戻す必要があります。この値は、オブジェクト(宣言されていない暗黙的なSELFパラメータ)が、宣言されているパラメータ・オブジェクトより小さいか、等しいかまたは大きいかを示します。

マップ・メソッドと同様、オーダー・メソッドを定義した場合、その型を持つ2つのオブジェクトを比較する必要があれば、自動的にコールされます。

オーダー・メソッドは、比較セマンティクスが複雑すぎてマップ・メソッドが使用できない場合に役立ちます。

例2-11に、建物番号で場所を比較するオーダー・メソッドを示します。

例2-11 オーダー・メソッドの作成および起動

DROP TYPE location_typ FORCE;
-- above necessary if you have previously created object
CREATE OR REPLACE TYPE location_typ AS OBJECT (
building_no  NUMBER,
city         VARCHAR2(40),
ORDER MEMBER FUNCTION match (l location_typ) RETURN INTEGER );/
CREATE OR REPLACE TYPE BODY location_typ AS
ORDER MEMBER FUNCTION match (l location_typ) RETURN INTEGER IS
BEGIN
IF building_no < l.building_no THEN
RETURN -1;               -- any negative number will do
ELSIF building_no > l.building_no THEN
RETURN 1;                -- any positive number will do
ELSE
RETURN 0;
END IF;
END;
END;/

-- invoking match method
DECLARE
loc location_typ;
secloc location_typ;
a number;

BEGIN
loc :=NEW location_typ(300, 'San Francisco');
secloc :=NEW location_typ(200, 'Redwood Shores');
a := loc.match(secloc);

DBMS_OUTPUT.PUT_LINE('order (1 is greater, -1 is lesser):' ||a); -- prints order:1
END;
/

注意:
導出元が別の型ではない型のみ、オーダー・メソッドが宣言できます。サブタイプはオーダー・メソッドを宣言できません。

比較メソッドのガイドライン

宣言できるのは、マップ・メソッドかオーダー・メソッドのいずれか一方で、両方を宣言することはできません。どちらのメソッド・タイプも、SQL文およびPL/SQLプロシージャ文を使用してオブジェクトを比較できます。ただし、どちらのメソッドも宣言しない場合でも、SQL文の中にあるオブジェクトについてのみ、等価比較または不等価比較が行えます。同じ型の2つのオブジェクトは、対応する属性の値が一致する場合のみ、等価とみなされます。

多数のオブジェクトをソートまたはマージする場合は、マップ・メソッドを使用し、これにより、すべてのオブジェクトがスカラー値にマップされた後、スカラー値がソートされます。オーダー・メソッドは繰り返してコールする必要があるため、効率的ではありません(一度に比較できるのは2つのオブジェクトのみです)。「オブジェクト比較のパフォーマンス」を参照してください。

型の階層内の比較メソッド

型階層で、ルート型(スーパータイプ)がマップ・メソッドとオーダー・メソッドのいずれも指定していない場合、どちらのメソッドもサブタイプになることはできません。

- 型の階層内のマップ・メソッド
ルート型がマップ・メソッドを指定している場合、そのサブタイプはいずれもマップ・メソッドをオーバーライドできます。ルート型がマップ・メソッドを定義していない場合、サブタイプはマップ・メソッドを定義できません。

- 型の階層内のオーダー・メソッド
オーダー・メソッドを定義できるのは、ルート型のみです。ルート型がオーダー・メソッドを定義していない場合、そのサブタイプはオーダー・メソッドを追加できません。

静的メソッド

静的メソッドはオブジェクトのインスタンスではなく、オブジェクト型に対して起動されます。静的メソッドは、型に対してグローバルに適用され、特定のオブジェクトのインスタンスのデータを参照する必要のない操作に使用します。静的メソッドは、SELFパラメータを持ちません。

静的メソッドは、STATIC FUNCTIONまたはSTATIC PROCEDUREを使用して宣言します。

静的メソッドは、たとえば次のように、ドット表記法によりメソッド・コールにオブジェクト型の名前を付けて修飾して起動します。

type_name.method()

設計上の考慮点は、「静的メソッド」を参照してください。

コンストラクタ・メソッド

コンストラクタ・メソッドは、ユーザー定義型の新しいインスタンスを戻し、その属性の値を設定するファンクションです。コンストラクタ・メソッドは、システム定義かユーザー定義のいずれかです。

コンストラクタを起動するには、キーワードNEWを使用できますが、必ずしもそうする必要はありません。

関連項目:
例2-10および「オブジェクトのコンストラクタとメソッドに対するコール」

システム定義コンストラクタ

デフォルトでは、属性を持つすべてのオブジェクト型についてコンストラクタ・ファンクションが暗黙的に定義されます。このコンストラクタは、属性値コンストラクタと呼ばれることもあります。

例2-1で定義されているperson_typオブジェクト型の場合、次の起動に示すように、コンストラクタ・メソッドの名前はオブジェクト型の名前になります。

person_typ (1, 'John Smith', '1-650-555-0135'),

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

ユーザー独自のコンストラクタ・ファンクションを定義して、ユーザー定義型を作成および初期化することもできます。デフォルトのシステム定義コンストラクタ(属性値コンストラクタ)はすでに存在するため便利ですが、ユーザー定義コンストラクタには型進化に関する重要な利点があります。「ユーザー定義コンストラクタの利点」を参照してください。コレクションのユーザー定義コンストラクタの詳細は、「コレクションのコンストラクタ・メソッド」を参照してください。

コンストラクタ・メソッドのリテラル起動

コンストラクタ・メソッドのリテラル起動とは、(バインド変数とは対照的に)引数がリテラルか、またはさらに続くコンストラクタ・メソッドのリテラル起動のいずれかをとるコンストラクタ・メソッドのコールのことです。次に例を示します。

CREATE TABLE people_tab OF person_typ;

INSERT INTO people_tab VALUES (
person_typ(101, 'John Smith', '1-650-555-0135') );

外部実装メソッド

PL/SQLを使用して、他の言語で作成された外部のサブプログラムを起動できます。これにより、これらの言語の長所や機能を活用できます。

関連項目:
第4章「Oracleプログラム環境のオブジェクト・サポート」

SQLオブジェクト型の継承

SQLオブジェクト継承は、型階層を構成するオブジェクト型の系図に基づいています。型階層は、スーパータイプと呼ばれる親オブジェクト型と、親から導出されたサブタイプと呼ばれる1つ以上のレベルの子オブジェクト型で構成されます。

継承は、階層内のサブタイプを対応するスーパータイプに接続するメカニズムです。サブタイプは、その親タイプの属性およびメソッドを自動的に継承します。また、継承リンクも保持されます。サブタイプは、親の属性またはメソッドの変更を自動的に取得します。スーパータイプの属性またはメソッドが更新されると、サブタイプにおいてもこの更新が行われます。

注意:
単一継承のみがサポートされています。したがって、サブタイプは1つのみのスーパータイプから直接導出できます。複数のスーパータイプから導出することはできません。

型階層内でオブジェクト型を使用すると、顧客などのエンティティをモデル化したり、元の型を基にして顧客の特化された様々なサブタイプを定義することができます。このように定義した後、階層に対して操作を行い、それぞれの型を実装させ、専用の方法で操作を実行できます。

この項では、次の内容を説明します。

- スーパータイプおよびサブタイプ

- FINALとNOT FINALの型およびメソッドの定義

- サブタイプの作成

- NOT INSTANTIABLEとしての型およびメソッドの宣言

- メソッドのオーバーロードおよびオーバーライド

- 動的メソッド・ディスパッチ

- 型階層内の型の代入

- 列および行の代入性

- 新しく作成したサブタイプの代入可能な列への格納

- 代入可能な列の作成後のサブタイプの削除

- 新しい表での代入性の無効化

- 代入性の制約

- 代入性の変更

- 代入性の変更の制限事項

- 型をまたがる代入

スーパータイプおよびサブタイプ

サブタイプは、スーパータイプから直接または他のサブタイプを介して間接的に導出できます。スーパータイプは、兄弟関係にあるサブタイプを複数持つことができますが、サブタイプが持つことができる直系の親スーパータイプは1つのみです(単一継承)。

図2-1 型階層内のスーパータイプおよびサブタイプ

スーパータイプからサブタイプを導出するには、親から継承したセットに新しい属性およびメソッドを追加するスーパータイプの特殊な異型を定義するか、継承したメソッドを再定義(オーバーライド)します。たとえば、person_typオブジェクト型からは、特殊な異型であるstudent_typやemployee_typを導出できます。これらのサブタイプは、根本的にはperson_typですが、特殊な種類の個人です。サブタイプが親から受け取った属性またはメソッドに加えられたなんらかの変更が、サブタイプと親のスーパータイプを区別するものとなります。

継承したメソッドを再定義しない場合、サブタイプには常に親タイプが持つ属性およびメソッドの同じコア・セットと、自身が追加する属性とメソッドが含まれます。person_typオブジェクト型がidno、nameおよびphoneという3つの属性と、メソッドget_idno()を持つ場合、person_typから導出されたオブジェクト型は、これらと同じ3つの属性とメソッドget_idno()を持つことになります。person_typの定義を変更すると、サブタイプの定義も変更されます。

サブタイプは、次のようにキーワードUNDERを使用して作成します。

CREATE TYPE student_typ UNDER person_typ

関連項目:
完全な例は、例2-15を参照してください。

サブタイプの属性またはメソッドは、次の方法で特化します。

- 親スーパータイプが持たない新しい属性を追加します。
たとえば、majorの属性を追加して、person_typの特殊な種類としてstudent_typを特化します。サブタイプは、親から継承した属性の型の削除や変更はできず、新しい属性を追加するのみです。

- 親スーパータイプにない新しいメソッドを追加します。

- サブタイプのバージョンで親のバージョンとは異なるコードが実行されるように、サブタイプが継承するメソッドの一部の実装を変更します。
たとえば、ellipseオブジェクトがメソッドcalculate()を定義するとします。ellipse_typの2つのサブタイプであるcircle_typおよびsphere_typが、それぞれ別の方法でこのメソッドを実装することができます。

関連項目:
「メソッドのオーバーロードおよびオーバーライド」

スーパータイプとそのサブタイプの間の継承関係が、オブジェクトの能力の大半をもたらす原因になっていると同時に、オブジェクトを複雑にする原因にもなっています。スーパータイプのメソッドが変更でき、再コンパイルするのみですべての下位サブタイプにこの変更を反映させることができるというのは、非常に強力な機能です。しかし、それは同時に、型を特化するか、それともメソッドを再定義するかを考慮する必要があるということでもあります。また、階層内の任意の型を表や列に入れることができるというのは強力な機能ですが、特定の場合にこれを行うかどうかを決定する必要があります。さらに、必要な範囲の型のみが型階層から選択されるように、DML文や問合せに制約を付ける必要があることもあります。

FINALとNOT FINALの型およびメソッドの定義

オブジェクト型を継承可能にするには、オブジェクト型定義でそれが継承可能であることを指定する必要があります。これにより、そこからサブタイプを導出できます。メソッドの場合は、定義でオーバーライドが可能かどうかを指定する必要があります。型とメソッドのどちらにも、キーワードFINALまたはNOT FINALが使用されます。

オブジェクト型を継承可能にして、そのオブジェクト型からサブタイプを導出できるようにするには、オブジェクト定義でそのように指定する必要があります。メソッドの場合は、定義でオーバーライドが可能かどうかを指定する必要があります。型とメソッドのどちらにも、キーワードFINALまたはNOT FINALが使用されます。

- 型の場合、FINAL(デフォルト)は、この型からサブタイプを導出できないことを意味します。NOT FINALは、サブタイプを導出できることを意味します。

- メソッドの場合、FINALは、サブタイプは自身の実装を組み込むことでメソッドをオーバーライドすることはできないことを意味します。NOT FINAL(デフォルト)は、スーパータイプのメソッドをオーバーライドできることを意味します。

オブジェクトの型およびメソッドの定義では、例2-12および例2-13に示すように、型およびメソッドの宣言にNOT FINALまたはFINALキーワードを使用します。

例2-12 NOT FINALとしてのperson_typオブジェクト型の作成

DROP TYPE person_typ FORCE;
-- above necessary if you have previously created object

CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT FINAL;
/

例2-12では、person_typをNOT FINAL型として宣言して、person_typのサブタイプを定義できるようにしています。

例2-13では、FINALのメンバー・ファンクションが含まれるNOT FINALオブジェクト型を作成します。

例2-13 FINALメンバー・ファンクションが含まれるNOT FINALとしてのオブジェクト型の作成

DROP TYPE person_typ FORCE;
-- above necessary if you have previously created object

CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
FINAL MAP MEMBER FUNCTION get_idno RETURN NUMBER)
NOT FINAL;
/

FINAL型からNOT FINAL型への切替え、またその逆の切替えには、ALTER TYPE文を使用します。次に示す文は、person_typをFINAL型に変更します。

ALTER TYPE person_typ FINAL;

型をNOT FINALからFINALへ変更できるのは、ターゲット型がサブタイプを持たない場合のみです。

サブタイプの作成

サブタイプは、CREATE TYPE文を使用して作成します。この文は、UNDERキーワードにより、サブタイプの直系の親を指定します。

親オブジェクトまたはスーパータイプ・オブジェクトの作成

例2-14では、例2-15、例2-18および例2-19のサブタイプ定義を示すために、親またはスーパータイプのperson_typオブジェクトを作成します。

例2-14のshow()に注意してください。続くサブタイプの各例では、OVERRIDINGキーワードにより、親タイプのshow()ファンクションが各サブタイプの指定にオーバーライドされています。

例2-14 親またはスーパータイプのperson_typオブジェクトの作成

DROP TYPE person_typ FORCE;
-- if created
CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;
/

CREATE OR REPLACE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
-- function that can be overriden by subtypes
MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN 'Id: ' || TO_CHAR(idno) || ', Name: ' || name;
END;

END;
/

サブタイプのオブジェクトの作成

サブタイプが継承するものは次のとおりです。

- スーパータイプに宣言または継承されているすべての属性

- スーパータイプに宣言または継承されているすべてのメソッド

例2-15では、student_typオブジェクトをperson_typのサブタイプとして定義し、person_typで宣言または継承されているすべての属性とperson_typで継承または宣言されているすべてのメソッドを、このオブジェクトで継承します。

例2-15 UNDER句を使用したstudent_typサブタイプの作成

-- requires Ex. 2-14
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30),
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;
/

CREATE TYPE BODY student_typ AS
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN (self AS person_typ).show || ' -- Major: ' || major ;
END;

END;
/

student_typの定義文は、2つの新しい属性(dept_idおよびmajor)を追加してperson_typを特化し、showメソッドをオーバーライドしています。サブタイプの中で宣言する新しい属性には、自身の型階層内の上位に位置するそのスーパータイプのいずれかに宣言されている属性またはメソッドとは別の名前を持たせる必要があります。

一般的な起動

一般的な起動は、特定のサブタイプ・メンバー・メソッドではなく、スーパータイプまたは親タイプのメソッドを起動するメカニズムを提供します。例2-15は、次の構文を使用してこのことを示しています。

(SELF AS person_typ).show

student_typ showメソッドは、person_typ showメソッドをコールして一般的な処理を実行した後で、そのperson_typ showメソッドによって戻された値に'--Major:'を追加するという独自の処理を実行します。このように、サブタイプのメソッドのオーバーライドは、対応する親タイプのメソッドのオーバーライドをコールし、一般的な処理を実行してから独自の処理を実行できます。

メソッドは、標準のメンバー・メソッド同様に起動されます。ただし、ASの後の型名は、式が評価する型の親タイプの型名である必要があります。

例2-16には、標準のメンバー・メソッド起動時の暗黙的自己引数に似た暗黙的SELF引数が示されています。この場合は、限定的なstudent_typ showメソッドではなく、person_typ showメソッドが起動されます。

例2-16 一般的な起動の使用

-- Requires Ex. 2-14 and 2-15
DECLARE
myvar student_typ := student_typ(100, 'Sam', '6505556666', 100, 'Math');
name VARCHAR2(100);
BEGIN
name := (myvar AS person_typ).show; --Generalized invocation
END;
/

メンバー・メソッドの起動と同様に、一般的な式もメソッドが明示的自己引数で起動される場合にサポートされます。

例2-17 一般的な式の使用

-- Requires Ex. 2-14 and 2-15
DECLARE
myvar2 student_typ := student_typ(101, 'Sam', '6505556666', 100, 'Math');
name2 VARCHAR2(100);
BEGIN
name2 := person_typ.show((myvar2 AS person_typ)); -- Generalized expression
END;
/

この例で二重カッコを使用しているのは、((myvar2 AS person_typ))は解決が必要な式であると同時にshowファンクションのパラメータでもあるためです。

注意:
コンストラクタ・メソッドの起動にこの構文は使用できません。また、この構文でASの後に示される型名は、メソッドが起動される式の型の親タイプの名前である必要があります。
この構文を使用できるのは、対応する親タイプのメンバー・メソッドのオーバーライドを起動する場合のみです。

複数のサブタイプ

型には、複数の子サブタイプを持たせることができ、これらの子サブタイプにもサブタイプを持たせることができます。例2-18では、例2-15で作成した既存のサブタイプstudent_typに加えて、person_typの下に別のサブタイプemployee_typを作成します。

例2-18 UNDER句を使用したemployee_typサブタイプの作成

-- requires Ex. 2-14

DROP TYPE employee_typ FORCE;
-- if previously created
CREATE OR REPLACE TYPE employee_typ UNDER person_typ (
emp_id NUMBER,
mgr VARCHAR2(30),
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2);
/

CREATE OR REPLACE TYPE BODY employee_typ AS
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN (SELF AS person_typ).show|| ' -- Employee Id: '
|| TO_CHAR(emp_id) || ', Manager: ' || mgr ;
END;

END;
/

別のサブタイプの下に、サブタイプを定義できます。この場合も、新しく定義されたサブタイプは、その親タイプが持つすべての属性およびメソッド(宣言されているもの、および継承されたもの)を継承します。例2-19では、例2-15で作成したstudent_typの下に新規のサブタイプpart_time_student_typを定義します。この新しいサブタイプは、student_typのすべての属性およびメソッドを継承し、別の属性number_hoursを追加します。

例2-19 UNDER句を使用したpart_time_student_typサブタイプの作成

CREATE TYPE part_time_student_typ UNDER student_typ (
number_hours NUMBER,
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2);
/

CREATE TYPE BODY part_time_student_typ AS
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN (SELF AS person_typ).show|| ' -- Major: ' || major ||
', Hours: ' || TO_CHAR(number_hours);
END;

END;
/

スーパータイプおよびサブタイプのオブジェクトを持つ表の作成

例2-20のperson_obj_tableに示すように、スーパータイプおよびサブタイプのインスタンスを含む表を作成して表にデータを移入できます。

例2-20 オブジェクト表の代入可能な行への値の挿入

CREATE TABLE person_obj_table OF person_typ;

INSERT INTO person_obj_table
VALUES (person_typ(12, 'Bob Jones', '650-555-0130'));

INSERT INTO person_obj_table
VALUES (student_typ(51, 'Joe Lane', '1-650-555-0140', 12, 'HISTORY'));

INSERT INTO person_obj_table
VALUES (employee_typ(55, 'Jane Smith', '1-650-555-0144',
100, 'Jennifer Nelson'));

INSERT INTO person_obj_table
VALUES (part_time_student_typ(52, 'Kim Patel', '1-650-555-0135', 14,
'PHYSICS', 20));

次のように、表のスーパータイプとサブタイプについてshow()ファンクションをコールできます。

SELECT p.show() FROM person_obj_table p;

出力は次のようになります。

Id: 12, Name: Bob Jones
Id: 51, Name: Joe Lane -- Major: HISTORY
Id: 55, Name: Jane Smith -- Employee Id: 100, Manager: Jennifer Nelson
Id: 52, Name: Kim Patel -- Major: PHYSICS, Hours: 20

show()メソッドが表示するデータは、オブジェクトがスーパータイプかサブタイプか、またサブタイプのshow()メソッドがオーバーライドされているかどうかで異なることに注意してください。たとえば、Bob Jonesはperson_typ、つまりスーパータイプです。nameとIdのみが表示されます。Joe Laneはstudent_typで、nameとIdはスーパータイプのshow()ファンクションから提供され、majorはサブタイプのオーバーライドされたshow()ファンクションから提供されます。

NOT INSTANTIABLEとしての型およびメソッドの宣言

型およびメソッドは、作成時にNOT INSTANTIABLEとして宣言できます。

- NOT INSTANTIABLE型
型がNOT INSTANTIABLEの場合、その型のインスタンスはインスタンス化できません。その型に(デフォルトまたはユーザー定義を問わず)コンストラクタはありません。これを型に使用するとすれば、その型をスーパータイプとしてのみ使用し、そこから特化されたサブタイプをインスタンス化する場合です。

- NOT INSTANTIABLEメソッド
インスタンス化不可のメソッドは、プレースホルダの役目を果します。これは宣言されますが、型の中に実装されません。すべてのサブタイプにおいてそれぞれ独自の方法でメソッドをオーバーライドする場合に、インスタンス化不可のメソッドを定義します。この場合、スーパータイプにメソッドを定義しても有益ではありません。

インスタンス化不可のメソッドを含む型は、例2-21のように、その型自体をインスタンス化不可として定義する必要があります。

例2-21 NOT INSTANTIABLEとしてのオブジェクト型の作成

DROP TYPE person_typ FORCE;
-- if previously created
CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
NOT INSTANTIABLE MEMBER FUNCTION get_idno RETURN NUMBER)
NOT INSTANTIABLE NOT FINAL;/

インスタンス化不可の継承メソッドが、サブタイプにおいても実装されない場合、スーパータイプと同様にサブタイプそのものをインスタンス化不可として定義する必要があります。インスタンス化不可のサブタイプは、インスタンス化不可のスーパータイプの下に定義できます。

インスタンス化可能な型からインスタンス化不可の型への切替え、またその逆の切替えには、ALTER TYPE文を使用します。次の例では、ALTER TYPE文がperson_typをインスタンス化可能な型にします。

例2-22 INSTANTIABLEへのオブジェクト型の変更

CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT INSTANTIABLE NOT FINAL;/
ALTER TYPE person_typ INSTANTIABLE;

インスタンス化可能な型からインスタンス化不可の型に変更できる型は、その型を直接または別の型やサブタイプを介して間接的に参照する列、ビュー、表またはインスタンスを持たないものに限定されます。

インスタンス化不可の型をFINALとして宣言することはできません(宣言しても、意味がありません)。

メソッドのオーバーロードおよびオーバーライド

サブタイプは自身が継承するメソッドを再定義できる他、同名のメソッドなど、新しいメソッドを追加することも可能です。

「サブタイプの作成」の例および例8-10を参照してください。

メソッドのオーバーロード

継承されたメソッドと同名の新しいメソッドをサブタイプに追加することを、オーバーロードといいます。同じユーザー定義型に名前が同じでシグネチャが異なるメソッドが存在する場合、それらのメソッドはオーバーロードと呼ばれます。メソッド・シグネチャは、メソッドの名前、数値、型、およびメソッドの仮パラメータ(暗黙的なselfパラメータなど)の順序で構成されます。

様々な動作方法を用意するには、オーバーロードが役立ちます。たとえば、ellipseオブジェクトは、異なる形態の計算を可能にするためにcalculate()メソッドを別のcalculate()メソッドでオーバーロードできます。

1つの型にオーバーロードされたメソッドが複数ある場合、コンパイラはメソッド・シグネチャを使用して、どのメソッドをコールするかを判断します。

次の疑似コードのサブタイプcircle_typは、calculate()のオーバーロードを作成します。

CREATE TYPE ellipse_typ AS OBJECT (...,
MEMBER PROCEDURE calculate(x NUMBER, x NUMBER),
) NOT FINAL;

CREATE TYPE circle_typ UNDER ellipse_typ (...,
MEMBER PROCEDURE calculate(x NUMBER),
...);
circle_typには、2つのバージョンのcalculate()が含まれます。1つは、NUMBERパラメータを2つ持つ継承されたバージョンで、もう1つはNUMBERパラメータを1つ持つ新しく作成されたメソッドです。

メソッドのオーバーライドおよび隠蔽

あるサブタイプの動作をカスタマイズするために、継承されたメソッドを再定義することを、メンバー・メソッドの場合はオーバーライド、静的メソッドの場合は隠蔽といいます。

オーバーロードとは異なり、新しいメソッドは作成せず、キーワードOVERRIDINGを使用して既存のメソッドを再定義するだけです。

オーバーライドおよび隠蔽は、サブタイプにおいて継承メソッドにこれまでとは異なる動作をさせるために、継承メソッドを再定義することです。たとえば、ellipse_typスーパータイプから導出されたサブタイプcircle_typは、円の面積を求めるようにメンバー・メソッドcalculate()をカスタマイズするために、このメソッドをオーバーライドします。メソッドをオーバーライドする例は、「サブタイプの作成」を参照してください。

いずれの場合も、サブタイプで再定義されたメソッドのバージョンが、同じ名前およびシグネチャを持つ元のバージョンを隠し、サブタイプのインスタンスがメソッドを起動する際には、元のバージョンのかわりに新しいバージョンが実行されるという点では、オーバーライドと隠蔽は似ています。サブタイプ自身がサブタイプを持つ場合は、元のメソッドではなく、再定義されたメソッドを継承します。

オーバーライドの場合、実行するメソッドの正しいバージョンを動的に選択するために、システムは、メンバー・メソッドの暗黙的自己引数に含まれている型情報に依存します。隠蔽の場合、正しいバージョンはコンパイル時に識別されるため、動的ディスパッチは必要ありません。「動的メソッド・ディスパッチ」を参照してください。

メソッドをオーバーライドまたは隠蔽するには、メソッドのシグネチャを保持する必要があります。メソッドのオーバーロードは、すべて同じ名前を持つため、コンパイラはサブタイプのメソッドのシグネチャを使用して、置き換えられるスーパータイプのバージョンを識別します。

CREATE TYPE BODY文の中でOVERRIDINGキーワードを使用してオーバーライドを通知します。サブタイプが静的メソッドを隠蔽する場合、これは必要ありません。

次の疑似コードでは、サブタイプがメソッドcalculate()をオーバーライドしていることを通知しています。

CREATE TYPE ellipse_typ AS OBJECT (...,
MEMBER PROCEDURE calculate(),
FINAL MEMBER FUNCTION function_mytype(x NUMBER)...
) NOT FINAL;

CREATE TYPE circle_typ UNDER ellipse_typ (...,
OVERRIDING MEMBER PROCEDURE calculate(),
...);

この階層のダイアグラムは、図2-2を参照してください。

メソッドのオーバーライドの制限事項

メソッドのオーバーライドには、次の制限事項があります。

- オーバーライドできるメソッドは、スーパータイプでFINALとして宣言されていないもののみです。

- オーダー・メソッドが出現する可能性があるのは、型階層のルート型のみで、サブタイプで再定義(オーバーライド)することはできません。

- サブタイプの静的メソッドにより、スーパータイプのメンバー・メソッドを再定義することはできません。

- サブタイプのメンバー・メソッドにより、スーパータイプの静的メソッドを再定義することはできません。

- オーバーライドされているメソッドが、いずれかのパラメータのデフォルト値を持つ場合は、そのパラメータのデフォルト値と同じものを、オーバーライドするメソッドに持たせる必要があります。

動的メソッド・ディスパッチ

動的メソッド・ディスパッチとは、現在の型または指定された型から上方向に型階層を調べて、実行時にメソッド・コールを最も近い実装にディスパッチする方法のことです。この機能は、メンバー・メソッドをオーバーライドするときにのみ使用可能であり、静的メソッドには適用されません。

メソッドのオーバーライドにより、型階層で同じメソッドの複数の実装を定義できます。次に示すellipse_typ型、circle_typ型、sphere_typ型の階層の中では、それぞれの型が異なる方法でcalculateメソッドを定義できます。

図2-2 型の階層

これらのメソッドの1つが起動されると、メソッドを起動したオブジェクト・インスタンスの型により、そのメソッドが使用する実装が決まります。次に、この実装にコールがディスパッチされ、実行されます。メソッド実装を選択するこのプロセスは、コンパイル時ではなく、実行時に処理されるため、仮想メソッド・ディスパッチまたは動的メソッド・ディスパッチと呼ばれます。

メソッド・コールは型階層を上方向に調べます。下方向には調べません。コールによりオブジェクト・インスタンスのメンバー・メソッドが起動される場合は、そのインスタンスの型が現在の型となり、その型で定義されているか、その型が継承した実装が使用されます。コールにより型の静的メソッドが起動された場合は、その型で定義されているか、その型が継承した実装が使用されます。

関連項目:
サブプログラム・コールの解決方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

型階層内の型の代入

型階層内で型を扱うときは、最も一般的なレベル(全員の選択や更新など)で作業する必要がある場合があります。しかし、学生のみ、または学生以外の個人のみなど、特定のサブタイプのみを選択または更新する必要がある場合もあります。

全員を選択し、宣言された型がperson_typのオブジェクトのみでなく、宣言されたサブタイプがstudent_typまたはemployee_typのオブジェクトも返す(多様な性質を持つ)機能は、代入性と呼ばれます。宣言された型がスーパータイプである変数または列に、スーパータイプの下位のサブタイプの1つが使用できる場合、スーパータイプは代入可能です。

一般的に、型は代入可能です。オブジェクト属性、コレクション要素およびREFは代入可能です。REF、型またはperson_typ型のコレクションとして定義された属性には、person_typのインスタンス、そのインスタンスのインスタンス、またはperson_typのサブタイプのインスタンスのREFを入れることができます。

サブタイプがスーパータイプの単なる特殊な種類である場合は、型が代入可能であることを期待します。ただし、形式上、サブタイプは元々型の1つで、上位のスーパータイプと同じ型ではありません。学生全員や、就業者全員など、個人全員が入っている列には、複数の型のデータが実際に格納されています。

基本的に、オブジェクト属性、コレクション要素およびREFは常に代入可能です。型定義のレベルでは、これらの代入性をあるサブタイプに制限する構文はありません。ただし、特定の表や列について、記憶域レベルの代入性を無効にすることも、制約を付けることもできます。「新しい表での代入性の無効化」および「代入性の制約」を参照してください。

列および行の代入性

オブジェクト表およびビューの中のオブジェクト型の列と行は代入可能です。つまり、特定の型の列または行にはその型とそのサブタイプのインスタンスを入れることができます。

たとえば、例2-14に示したような型階層person_typについて考えます。すべての型の行が含まれるperson_typのオブジェクト表を作成できます。このためには、例2-20で示したように、特定の型のインスタンスを、INSERT文のVALUES句の中でその型のコンストラクタを使用してオブジェクト表に挿入します。

同様に、例2-23に示すように、リレーショナル表またはビューで型person_typの代入可能列に3つの型すべてのインスタンスを入れることもできます。この例では、その型階層から個人、学生および定時制学生のオブジェクトを再作成して、person_typ列contactに挿入します。

例2-23 表の代入可能な列への値の挿入

DROP TYPE person_typ FORCE;
-- if previously created

DROP TYPE student_typ FORCE; -- if previously created

DROP TYPE part_time_student_typ FORCE; -- if previously created
DROP TABLE contacts; if previously created
CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT FINAL;/
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30))
NOT FINAL;
/
CREATE TYPE part_time_student_typ UNDER student_typ (
number_hours NUMBER);
/
CREATE TABLE contacts (
contact         person_typ,
contact_date    DATE );

INSERT INTO contacts
VALUES (person_typ (12, 'Bob Jones', '650-555-0130'), '24 Jun 2003' );

INSERT INTO contacts
VALUES (student_typ(51, 'Joe Lane', '1-650-555-0178', 12, 'HISTORY'),
'24 Jun 2003' );

INSERT INTO contacts
VALUES (part_time_student_typ(52, 'Kim Patel', '1-650-555-0190', 14,
'PHYSICS', 20), '24 Jun 2003' );

新しく作成したサブタイプは、代入可能な表およびそのスーパータイプの列のいずれにも(サブタイプを作成する前に存在していた表や列など)格納できます。

一般に、属性はドット表記法を使用してアクセスできます。1つの行または列の宣言された型のサブタイプの属性にアクセスするには、TREATファンクションを使用します。次に例を示します。

SELECT TREAT(contact AS student_typ).major FROM contacts;

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

代入可能な行でのOBJECT_VALUEおよびOBJECT_IDの使用

例2-24に示すように、OBJECT_VALUEおよびOBJECT_ID疑似列によって、オブジェクト表内の代入可能な行の値およびオブジェクト識別子(OID)にアクセスし、識別できます。

関連項目:
これらの疑似列の詳細は、『Oracle Database SQL言語リファレンス』を参照してください

例2-24 OBJECT_VALUEおよびOBJECT_IDの使用

DROP TABLE person_obj_table; -- required if previously created
CREATE TABLE person_obj_table OF person_typ;

INSERT INTO person_obj_table
VALUES (person_typ(20, 'Bob Jones', '650-555-0130'));

SELECT p.object_id, p.object_value FROM person_obj_table p;

スーパータイプの属性を持つサブタイプ

サブタイプは、型がスーパータイプの型である属性を持つことが可能です。次に例を示します。

例2-25 スーパータイプの属性を持つサブタイプの作成

-- requires Ex 2-22
CREATE TYPE student_typ UNDER person_typ (
dept_id   NUMBER,
major     VARCHAR2(30),
advisor   person_typ);
/

ただし、このタイプの列は代入可能ではありません。同様に、サブタイプは、要素の型がそのスーパータイプの1つになっているコレクション属性を持つことができますが、この場合もこのタイプの列は代入可能ではありません。たとえば、student_typにperson_typのネストした表またはVARRAYがある場合、student_typ列は代入可能ではありません。

ただし、スーパータイプを参照するREF属性を持つサブタイプの代入可能な列が定義できます。たとえば、例2-26に示すcomposite_category_typサブタイプには、ネストした表subcategory_ref_listが含まれています。この表には、category_typのREFであるsubcategory_ref_list_typが含まれています。サブタイプは、次のようにして作成されました。

例2-26 REF属性を持つサブタイプの列の定義

-- not to be executed
CREATE TYPE subcategory_ref_list_typ
AS TABLE OF REF category_typ;
/

CREATE TYPE composite_category_typ
UNDER category_typ
(
subcategory_ref_list subcategory_ref_list_typ
...

「新しい表での代入性の無効化」を参照してください。

REF列および属性の代入

REF列および属性は、ビューでも表でも代入可能です。たとえば、ビューまたは表のいずれでも、REF person_typとして宣言された列に、person_typまたはそのサブタイプのインスタンスの参照を入れることができます。

コレクション要素の代入

コレクション要素は、ビューでも表でも代入可能です。たとえば、person_typのネストした表には、person_typまたはそのサブタイプのオブジェクト・インスタンスを入れることができます。

新しく作成したサブタイプの代入可能な列への格納

サブタイプを作成すると、スーパータイプの代入可能な列をすでに持つ表に、新しいサブタイプも格納できるようになります。つまり、サブタイプの作成には、このような表の有無が影響します。このような表が存在する場合、代入可能なサブタイプ(表の制約に違反しないサブタイプ)のみ作成できます。

次の例で、person_typを作成してから、person_typの下にstudent_typサブタイプを作成しようとします。

例2-27 代入可能な列の作成後のサブタイプの作成

DROP TYPE person_typ FORCE;
DROP TABLE person_obj_table;
DROP TYPE student_typ;
-- perform above drops if objects/tables created
CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT FINAL;/

CREATE TABLE person_obj_table (p person_typ);

ただし、student_typはスーパータイプの属性を持ち、person_obj_table表に、スーパータイプの代入可能な列pがあるため、次の文は正常に実行されません。

CREATE TYPE student_typ UNDER person_typ ( -- incorrect CREATE subtype
advisor person_typ);
/

次の操作は正常に実行されます。このようなstudent_typサブタイプは、代入可能です。person_obj_table表は、自動的にこの新しい型のインスタンスを格納できるようになります。

CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30));/
INSERT INTO person_obj_table
VALUES (student_typ(51, 'Joe Lane', '1-650-555-0178', 12, 'HISTORY'));

代入可能な列の作成後のサブタイプの削除

VALIDATEオプションを使用してサブタイプを削除すると、スーパータイプの代入可能な列のいずれにもサブタイプのインスタンスが格納されていないことが確認されます。このようなインスタンスが存在しない場合は、DROP操作が完了します。

次の文は、person_obj_table表の代入可能な列pにstudent_typのインスタンスが格納されているため、正常に実行されません。

DROP TYPE student_typ VALIDATE -- incorrect: an instance still exists ;

型を削除するには、最初にスーパータイプの代入可能な列にあるそのインスタンスを削除します。

DELETE FROM person_obj_table WHERE p IS OF (student_typ);

DROP TYPE student_typ VALIDATE;

関連項目:
DROPおよびVALIDATEの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

新しい表での代入性の無効化

表を作成する際、列または属性(任意のレベルにネストされた埋込み属性やコレクションなど)についての代入性は、NOT SUBSTITUTABLE AT ALL LEVELS句により無効にできます。

次に示す句は、office_typインスタンスのみを格納するように、リレーショナル表のoffice列に制約を設定し、サブタイプのどのインスタンスも使用できなくします。

例2-28 表の作成時の代入性の無効化

DROP TYPE location_typ FORCE; -- required if previously created
DROP TYPE office_typ FORCE; -- required if previously created
CREATE OR REPLACE TYPE location_typ AS OBJECT (
building_no  NUMBER,
city         VARCHAR2(40) );
/

CREATE TYPE people_typ AS TABLE OF person_typ;
/
CREATE TYPE office_typ AS OBJECT (
office_id    VARCHAR(10),
location     location_typ,
occupant     person_typ )
NOT FINAL;/

CREATE TABLE dept_office (
dept_no      NUMBER,
office       office_typ)
COLUMN office NOT SUBSTITUTABLE AT ALL LEVELS;

オブジェクト表の場合は、次のように句を表全体に適用できます。

DROP TABLE office_tab; -- if previously created
CREATE TABLE office_tab OF office_typ
NOT SUBSTITUTABLE AT ALL LEVELS;

また、この句で特定の列(つまり、表のオブジェクト型の特定の属性)の代入性を無効にすることもできます。

DROP TABLE office_tab; -- if previously created
CREATE TABLE office_tab OF office_typ
COLUMN occupant NOT SUBSTITUTABLE AT ALL LEVELS;

次のような構文を使用すると、コレクションの要素型が代入性を持たないように指定できます。

DROP TABLE people_tab;
-- required if previously created
CREATE TABLE people_tab (
people_column people_typ )
NESTED TABLE people_column
NOT SUBSTITUTABLE AT ALL LEVELS STORE AS people_column_nt;

REF列の代入性を無効にするメカニズムはありません。

オブジェクト列に制約を付けるには、NOT SUBSTITUTABLE AT ALL LEVELSかIS OF typeのいずれか一方のみが使用可能で、両方は使用できません。

代入性の制約

オブジェクト列または属性で許可されているサブタイプの範囲を、宣言された型の階層内の特定のサブタイプに制限するように、制約を加えることができます。これを行うには、IS OF typeの制約を使用します。

次の文は、占有者が従業員のみに限定されるoffice_typの表を作成します。

例2-29 表の作成時の代入性の制約

DROP TABLE office_tab;
-- if previously created
CREATE TABLE office_tab OF office_typ
COLUMN occupant IS OF (ONLY employee_typ);

office_typ型がperson_typ型の占有者を許可している場合でも、列宣言によりemployee_typのインスタンスのみを格納するように制約されます。

行オブジェクトおよび列オブジェクトを(複数ではなく)1つのサブタイプに限定する場合、使用できるのはIS OF typeの演算子のみで、前述の例のようにONLYキーワードを使用する必要があります。

オブジェクト列に制約を付けるには、IS OF typeかNOT SUBSTITUTABLE AT ALL LEVELSのいずれか一方のみが使用可能で、両方は使用できません。

代入性の変更

既存の表で、ALTER TABLE文を使用して、オブジェクト列をSUBSTITUTABLEからNOT SUBSTITUTABLE(またはNOT SUBSTITUTABLEからSUBSTITUTABLE)に変更できます。これを行うには、特定の列に対し、[NOT] SUBSTITUTABLE AT ALL LEVELS句を指定します。

代入性は、特定の列に対してのみ変更できます。オブジェクト表全体の代入性は変更できません。

次の文により、列officeが代入可能になります。

例2-30 表内の代入性の変更

-- Requires Ex. 2-28
ALTER TABLE dept_office
MODIFY COLUMN office SUBSTITUTABLE AT ALL LEVELS;

次の文により、列が代入不可になります。FORCEキーワードも使用されている点に注意してください。このキーワードは、サブタイプ属性の型ID情報またはデータが含まれている非表示列を削除します。

ALTER TABLE  dept_office
MODIFY COLUMN office NOT SUBSTITUTABLE AT ALL LEVELS FORCE;

列を代入不可にする際にFORCEキーワードを使用しない場合、列および型の全属性をFINALにしないと、ALTER TABLE文の実行は失敗します。

VARRAY列は、VARRAY自体の要素型がFINALであり、FINALでない埋込み型を所有しない場合(自らの属性内、または埋込み型の属性内に)のみ、SUBSTITUTABLEからNOT SUBSTITUTABLEに変更できます。

型IDおよびサブタイプ属性の非表示列の詳細は、「代入可能な列およびオブジェクト表の非表示列」を参照してください。

代入性の変更の制限事項

ALTER TABLE文では、一度に1列の代入性のみ変更できます。複数の列の代入性を変更する場合、複数の文を発行する必要があります。

オブジェクト表では、表の作成時に代入性が表レベルで明示的に設定されていない場合のみ、列の代入性を変更できます。

たとえば、次の例では、CREATE TABLE文により、代入性が明示的に表レベルで有効または無効に設定されていないため、列アドレスの代入性の変更は成功します。

DROP TABLE office_tab;
-- if previously created
CREATE TABLE office_tab OF office_typ;

ALTER TABLE office_tab
MODIFY COLUMN occupant NOT SUBSTITUTABLE AT ALL LEVELS FORCE;

ただし、次の例では、代入性が表レベルで明示的に設定されているため、列アドレスの設定の変更は失敗します。

DROP TABLE office_tab;
-- if previously created
CREATE TABLE office_tab OF office_typ
NOT SUBSTITUTABLE AT ALL LEVELS;

/* Following SQL statement generates an error: */
ALTER TABLE office_tab
MODIFY COLUMN occupant SUBSTITUTABLE AT ALL LEVELS FORCE  -- incorrect ALTER;

IS OF type演算子によってすでに代入性が制約されている列は、[NOT] SUBSTITUTABLE AT ALL LEVELS句によって代入性を変更することはできません。IS OF typeの詳細は、「代入性の制約」を参照してください。

型をまたがる代入

この項で説明する代入規則は、INSERT/UPDATE文、RETURNING句、ファンクションのパラメータ、およびPL/SQL変数に適用されます。

オブジェクト代入の代表的なオブジェクト

代入性とは、上位のスーパータイプの1つの代理を務めるサブタイプの能力のことです。サブタイプのかわりにスーパータイプを使用するなど、逆の方向で置換を行うと、コンパイル時にエラーが発生します。

型source_typのソースを型target_typのターゲットに代入するパターンは、次のいずれかである必要があります。

- ケース1: source_typおよびtarget_typが同一型である。

- ケース2: source_typがtarget_typのサブタイプである(ワイドニング)。

ケース2は、ワイドニングを示しています。ワイドニングとは、ターゲットが宣言された型よりも、ソースが宣言された型の方が範囲が特定される代入のことです。従業員インスタンスを個人タイプの変数に代入する処理は、その例です。

個人の範囲を絞って定義し、対象を特化したのが従業員であるため、個人をさらに特化して従業員にする存在を無視する場合、個人用のスロットに従業員を入れることができます。すべての従業員が個人のため、ワイドニングは常に機能します。

次の表を使用して、ワイドニングについて説明します。

TABLE T(pers_col person_typ, emp_col employee_typ,
stu_col student_typ)

次に示す代入は、ワイドニングを示しています。perscolが代入不可と定義されていないかぎり、代入は有効です。

UPDATE T set pers_col = emp_col;

次の例のPL/SQLでは、最初にperson_typおよびemployee_typを作成する必要があります。

例2-31 PL/SQLの代入

DROP TYPE person_typ FORCE;
-- if previously created
CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT FINAL;
/
DROP TYPE employee_typ FORCE; -- if previously created
CREATE TYPE employee_typ UNDER person_typ (
emp_id NUMBER,
mgr VARCHAR2(30));
/
-- PL/SQL assignment example
DECLARE
var1 person_typ;
var2 employee_typ;
BEGIN
var2 := employee_typ(55, 'Jane Smith', '1-650-555-0144', 100, 'Jennifer Nelson');
var1 := var2;
END;
/

ナローイング代入

ナローイング代入はワイドニングの逆です。個人など、一般化した広い範囲を対象とする型を、従業員など範囲を限定して定義された型とみなすことを意味します。すべての個人が従業員であるとはかぎらないため、このような特定の代入は、該当する個人が偶然に従業員の場合のみ機能します。このため最終的には、「オブジェクト代入の代表的なオブジェクト」に示したように、ナローイング代入はケース1のような場合にしか機能しません。

ナローイング代入を行うには、TREATファンクションを使用して、より一般的な宣言型のソース・インスタンスが実際には限定されたターゲット型のインスタンスであり、そのように操作可能であることをテストする必要があります。TREATファンクションは実行時にこのことを確認するためのチェックを行い、ソース値(該当する個人)がターゲット型でもサブタイプの1つでもない場合は、NULLを戻します。

たとえば、次のUPDATE文は、列perscolのperson_typの値を、employee_typの列empcolに設定します。perscolのそれぞれの値についての代入が成功するのは、この個人が従業員でもある場合です。個人が従業員ではない場合、TREATはNULLを戻し、代入がNULLに戻ります。

UPDATE T set emp_col = TREAT(pers_col AS employee_typ);

次の文は、ソース値の宣言された型を明示的に変更せずに、代入のナローイングを試行します。この文は、エラーを戻す結果になります。

UPDATE T set emp_col = pers_col;

「ナローイング代入でのTREATの使用」を参照してください。

コレクションの代入

コレクション型の式の代入では、ソースの宣言された型がターゲットのそれと一致する必要があります。コレクションの代入では、ワイドニングとナローイングのどちらも使用できません。しかし、スーパータイプのコレクションにサブタイプ値を代入できます。たとえば、新しいstudent_typを作成した後、次のようなコレクション型があるとします。

例2-32 コレクションperson_setの作成

-- Requires 2-21
DROP student_typ;
-- if previously created
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30))
NOT FINAL;
/
CREATE TYPE person_set AS TABLE OF person_typ;
/

CREATE TYPE student_set AS TABLE OF student_typ;
/

これらの異なるコレクション型の式を相互に代入することはできませんが、student_typのコレクション要素はperson_set型のコレクションに代入できます。

DECLARE
var1 person_set;
var2 student_set;
elem1 person_typ;
elem2 student_typ;
BEGIN
--  var1 := var2;   /* ILLEGAL - collections not of same type */
var1 := person_set (elem1, elem2);   /* LEGAL : Element is of subtype */
END;
/

オブジェクトに便利なファンクションおよび演算子

次に、オブジェクトやオブジェクトの参照を扱う際に特に役立つファンクションや演算子を示します。

- CAST

- CURSOR

- DEREF

- IS OF type

- REF

- SYS_TYPEID

- TABLE()

- TREAT

- VALUE

使用例は、このマニュアルの他の章でも示しています。

PL/SQLの場合、VALUE、REFおよびDEREFファンクションが現れるのは、SQL文の中のみです。SQLファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CAST

CASTは、ある組込みデータ型またはコレクション型の値を、別の組込みデータ型またはコレクション型の値に変換します。次に例を示します。

例2-33 CASTファンクションの使用

CREATE TYPE person_list_typ AS TABLE OF person_typ;/

SELECT CAST(COLLECT(contact) AS person_list_typ)
FROM contacts;

SQL CASTファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CURSOR

CURSOR式は、ネストしたカーソルを戻します。この形式の式は、PL/SQLのREF CURSORと同等で、REF CURSOR引数としてファンクションに渡すことが可能です。

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

DEREF

SQL文のDEREFファンクションは、REFに対応するオブジェクト・インスタンスを戻します。DEREFにより戻されるオブジェクト・インスタンスは、REFの宣言された型か、またはこの型のサブタイプになる可能性があります。

次に示す文は、表contact_refからperson_typオブジェクトを戻します。

例2-34 DEREFファンクションの使用

SELECT DEREF(c.contact_ref), c.contact_date
FROM contacts_ref c;

「REFの参照解除」を参照してください。SQL DEREFファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

IS OF type

IS OF typeの述語は、オブジェクト・インスタンスの型の特化レベルを検査します。

たとえば、次の問合せでは、person_obj_table表に格納されている学生インスタンス(学生のすべてのサブタイプなど)がすべて取り出されます。

例2-35 IS OF type演算子を使用したサブタイプ値の問合せ

SELECT VALUE(p)
FROM person_obj_table p
WHERE VALUE(p) IS OF (student_typ);

指定されたサブタイプではないオブジェクト、または指定されたサブタイプのサブタイプに対しては、IS OFよりFALSEが戻されます。指定されたサブタイプのサブタイプは、指定されたサブタイプのさらに特化されたバージョンにすぎません。このようなサブタイプを除外するには、ONLYキーワードが使用できます。このキーワードを使用すると、IS OFは指定された型を除くすべての型に対してFALSEを戻します。

次に示す文は、個人、従業員および学生が入っているオブジェクト表person_obj_tableのオブジェクトを検証し、指定された2つの個人サブタイプであるemployee_typおよびstudent_typ(そのサブタイプが存在する場合は、これらのサブタイプも含まれます)のオブジェクトのみに対するREFを戻します。

SELECT REF(p)
FROM person_obj_table p
WHERE VALUE(p) IS OF (employee_typ, student_typ);

次に、PL/SQLの同様の例を示します。個人が従業員または学生の場合、コードによって操作が実行されます。

DECLARE
var person_typ;
BEGIN
var := employee_typ(55, 'Jane Smith', '1-650-555-0144', 100, 'Jennifer Nelson');
IF var IS OF (employee_typ, student_typ) THEN
DBMS_OUTPUT.PUT_LINE('Var is an employee_typ or student_typ object.');
ELSE
DBMS_OUTPUT.PUT_LINE('Var is not an employee_typ or student_typ object.');
END IF;
END;
/

次の文は、最も狭い意味での型または特化された型がstudent_typである学生のみを戻します。表またはビューにstudent_typのサブタイプ(part_time_student_typなど)のオブジェクトが含まれている場合、これらのオブジェクトは除外されます。この例は、TREATファンクションを使用して、学生オブジェクトをビューの宣言された型person_typからstudent_typに変換します。

SELECT TREAT(VALUE(p) AS student_typ)
FROM person_obj_table p
WHERE VALUE(p) IS OF(ONLY student_typ);

REFが示すオブジェクトの型を検証する場合、IS OF typeの述語を使用して検証する前に、REFの参照を解除するには、DEREFファンクションが使用できます。

たとえば、contact_refをREF person_typとして宣言すると、次に示すように学生についての行のみが取得できます。

SELECT *
FROM contacts_ref
WHERE DEREF(contact_ref) IS OF (student_typ);

SQL IS OF type条件の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

REF

SQL文のREFファンクションは、オブジェクト表またはビューの相関名(または表別名)を引数としてとり、その表またはビューからオブジェクト・インスタンスの参照(REF)を戻します。REFファンクションにより、表またはビューの宣言された型のオブジェクトの参照、またはその型のサブタイプのオブジェクトの参照が戻せます。たとえば、次の文は、idno属性が12である学生や従業員の参照など個人全員の参照を戻します。

例2-36 REFファンクションの使用

SELECT REF(p)
FROM person_obj_table p
WHERE p.idno = 12;

SQL REFファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

SYS_TYPEID

SYS_TYPEIDファンクションを問合せで使用すると、引数として渡されたオブジェクト・インスタンスの最も狭い意味での型の型ID (非表示の型)が戻されます。

オブジェクト・インスタンスの最も狭い意味での型とは、インスタンスが属する型(つまり、ルート型から最も離れたインスタンスから取り出される型)です。たとえば、Timが定時制の学生だとすると、彼は学生であると同時に個人ですが、彼の最も狭い意味での型は定時制の学生です。

このファンクションは、代入可能なすべての列と対応付けられた非表示の型判別式の列から型IDを戻します。FINALのルート型についてはNULLの型IDを戻します。

このファンクションの構文は、次のとおりです。

SYS_TYPEID(object_type_value)

SYS_TYPEIDファンクションを使用するには、オブジェクト型の引数を付ける必要があります。非表示の型判別式の列について索引が作成できるようにすることが、このファンクションの主な目的です。

型階層に属するすべての型に、型階層内で一意な非NULL型IDが割り当てられます。型階層に属さない型には、NULL型IDが与えられます。

FINALのルート型を除くすべての型が、型階層に属します。FINALのルート型には、継承により関連付けられる型はありません。

- これはFINALの型のため、そこから導出されるサブタイプを持つことはできません。

- ルート型自身が他の型から導出されることはないため、ルート型のスーパータイプは存在しません。

SYS_TYPEIDの例として、person_typの代入可能なオブジェクト表person_obj_tableを検討してみましょう。person_typは、サブタイプとしてstudent_typを持ち、student_typのサブタイプとしてpart_time_student_typを持つ階層のルート型です。例2-20を参照してください。

次の問合せでは、SYS_TYPEIDを使用します。このファンクションは、person_obj_table表の中にあるオブジェクト・インスタンスのname属性およびtypeidを取得します。インスタンスのそれぞれが、異なる型を持ちます。

例2-37 SYS_TYPEIDファンクションの使用

SELECT name, SYS_TYPEID(VALUE(p)) typeid FROM person_obj_table p;

型判別式の列および他の非表示列の詳細は、「代入可能な列およびオブジェクト表の非表示列」を参照してください。SQL SYS TYPEIDファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

TABLE()

テーブル・ファンクションとは、物理データベース表のように問い合せたり、PL/SQLのコレクション変数に割り当てることが可能な、行、ネストした表またはVARRAYのコレクションを生成するファンクションです。テーブル・ファンクションは、問合せのFROM句でデータベース表の名前のように使用したり、問合せのSELECTリストで列名のように使用できます。

テーブル・ファンクションは、行のコレクションを入力として取ることができます。入力コレクション・パラメータには、VARRAYやPL/SQL表のようなコレクション型か、またはREF CURSORを使用できます。

Oracle Databaseによりテーブル・ファンクションの結果が繰り返し戻されるようにするには、PIPELINEDを使用します。テーブル・ファンクションにより、ネストした表またはVARRAY型が戻されます。テーブル・ファンクションを問い合せるには、問合せのFROM句のファンクション名の前に、TABLEキーワードを使用します。

TABLE()ファンクションの詳細は、『Oracle Databaseデータ・カートリッジ開発者ガイド』および『Oracle Database PL/SQL言語リファレンス』を参照してください。

TREAT

TREATファンクションは、階層内の指定された異なる型(通常は、式の宣言された型のサブタイプ)として、特定の式を操作できるかを、実行時にチェックします。つまり、このファンクションは、スーパータイプのインスタンスをサブタイプのインスタンスとして扱おうとします(たとえば、個人を学生として扱います)。その人が学生であれば、学生が持つ可能性のある別の属性やメソッドと一緒に、学生として戻されます。その人が学生でない場合、TREATはSQLでNULLを戻します。

TREATは、主に次の2つの目的で使用します。

- ナローイング代入で、階層内のさらに特化された型の変数に式が代入できるように、式のタイプを変更するため(スーパータイプの値をサブタイプに設定するため)。

- 行または列の宣言された型のサブタイプの属性またはメソッドにアクセスするため。
型Tの代入可能なオブジェクト表または列には、Tのすべてのサブタイプのすべての属性についての非表示列があります。これらの非表示列にはサブタイプの属性データが含まれますが、DESCRIBE文でこれらの非表示列をリストすることはできません。TREATを使用すると、これらの列にアクセスできます。

ナローイング代入でのTREATの使用

ナローイング代入(スーパータイプの値をサブタイプに設定する代入)では、TREATファンクションを使用します。ワイドニング代入との違いは、「型をまたがる代入」を参照してください。

例2-38では、TREATにより、すべてのstudent_typインスタンスが、person_typ型(student_typのスーパータイプ)のperson_obj_tableから戻されます。この文は、TREATを使用して、pの型をperson_typからstudent_typに変更します。

例2-38 問合せで特定のサブタイプを戻すためのTREATファンクションの使用

SELECT TREAT(VALUE(p) AS student_typ)
FROM person_obj_table p;

それぞれのpについてTREATによる変更が成功するのは、pの値の最も狭い意味での型または特化された型がstudent_typか、そのサブタイプの1つである場合のみです。pが学生でない個人の場合、またはpがNULLの場合、TREATはSQLではNULLを戻し、PL/SQLでは例外を発行します。

REF式の宣言された型を変更する場合にも、TREATが使用できます。次に例を示します。

SELECT TREAT(REF(p) AS REF student_typ)
FROM person_obj_table p;

この例は、すべてのstudent_typインスタンスに対してREFを戻します。学生ではない個人インスタンスについては、SQLの場合はNULL REFが戻され、PL/SQLの場合は例外が発行されます。

サブタイプの属性またはメソッドにアクセスするためのTREATファンクションの使用

行または列の宣言された型のサブタイプの属性またはメソッドにアクセスするために使用するのが、おそらくTREATの最も重要な使用方法です。次の問合せでは、major属性を持つ個人、学生および定時制の学生全員のこの属性が取り出されます。学生ではない人については、NULLが戻されます。

例2-39 特定のサブタイプの属性にアクセスするためのTREATファンクションの使用

SELECT name, TREAT(VALUE(p) AS student_typ).major major
FROM person_obj_table p;

majorはstudent_typの属性であっても、表personsの宣言された型であるperson_typではないため、次の問合せは意図したとおりには機能しません。

SELECT name, VALUE(p).major major FROM person_obj_table p -- incorrect;

次に、PL/SQLの例を示します。

DECLARE
var person_typ;
BEGIN
var := employee_typ(55, 'Jane Smith', '1-650-555-0144', 100, 'Jennifer Nelson');
DBMS_OUTPUT.PUT_LINE(TREAT(var AS employee_typ).mgr);
END;
/

SQL TREATファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

VALUE

SQL文では、VALUEファンクションはオブジェクト表またはオブジェクト・ビューの相関変数(表の別名)を引数としてとり、表またはビューの行に対応するオブジェクト・インスタンスを戻します。VALUEファンクションにより、行の宣言された型のインスタンスか、またはその型のサブタイプを戻すことができます。

例2-40では、最初にpart_time_student_typを作成し、次に学生や従業員を含む個人全員がperson_typの表person_obj_tableから戻されるSELECT問合せを示しています。

例2-40 VALUEファンクションの使用

-- Requires Ex. 2-31 and 2-32
CREATE TYPE part_time_student_typ UNDER student_typ (
number_hours NUMBER);
/
SELECT VALUE(p) FROM person_obj_table p;

定時制の学生のみ、つまり最も狭い意味での型がpart_time_student_typであるインスタンスを取り出すには、ONLYキーワードを使用して選択範囲を限定します。

SELECT VALUE(p) FROM person_obj_table p
WHERE VALUE(p) IS OF (ONLY part_time_student_typ);

次の例では、オブジェクト表内のオブジェクト・インスタンスを更新するためにVALUEが使用されています。

UPDATE person_obj_table p
SET VALUE(p) = person_typ(12, 'Bob Jones', '1-650-555-0130')
WHERE p.idno = 12;

例5-22「VALUEによるネストした表の更新」も参照してください。SQL VALUEファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

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

この章では、PL/SQLでのオブジェクト型の使用方法を説明します。

内容は次のとおりです。

- PL/SQLでのオブジェクトの宣言と初期化

- PL/SQLでのオブジェクトの操作

- 継承を使用するPL/SQLでのオーバーロードの使用

- オブジェクトでの動的SQLの使用

PL/SQLでのオブジェクトの宣言と初期化

PL/SQLのブロック、サブプログラムまたはパッケージでオブジェクト型を使用する場合、2段階の操作を行います。

1. SQL*Plusまたはそれと同種のプログラムでは、CREATE TYPE SQL文を使用してオブジェクト型を定義する必要があります。

関連項目:
「オブジェクト型について」

オブジェクト型がスキーマに定義およびインストールされたら、その型はすべてのPL/SQLブロック、サブプログラムまたはパッケージにおいて使用できます。

2. その後、PL/SQLで、先の手順で定義したユーザー定義型またはADTをデータ型に持つ変数を宣言します。

オブジェクトおよびADTには、通常の有効範囲とインストール・ルールが適用されます。

オブジェクト型の定義

例3-1に、2つのオブジェクト型と、オブジェクト型の1つの表を示します。続く各例に、PL/SQLでこれらのオブジェクト型の変数を宣言し、これらのオブジェクトが関連するその他の操作を実行する方法を示します。

例3-1 オブジェクト型を使用した作業

CREATE TYPE address_typ AS OBJECT (
street          VARCHAR2(30),
city            VARCHAR2(20),
state           CHAR(2),
postal_code     VARCHAR2(6) );
/
CREATE TYPE employee_typ AS OBJECT (
employee_id       NUMBER(6),
first_name        VARCHAR2(20),
last_name         VARCHAR2(25),
email             VARCHAR2(25),
phone_number      VARCHAR2(20),
hire_date         DATE,
job_id            VARCHAR2(10),
salary            NUMBER(8,2),
commission_pct    NUMBER(2,2),
manager_id        NUMBER(6),
department_id     NUMBER(4),
address           address_typ,
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER PROCEDURE display_address ( SELF IN OUT NOCOPY employee_typ ) );
/
CREATE TYPE BODY employee_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN employee_id;
END;
MEMBER PROCEDURE display_address ( SELF IN OUT NOCOPY employee_typ ) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(first_name || ' '  || last_name);
DBMS_OUTPUT.PUT_LINE(address.street);
DBMS_OUTPUT.PUT_LINE(address.city || ', '  || address.state || ' ' ||
address.postal_code);
END;
END;
/
CREATE TABLE employee_tab OF employee_typ;

PL/SQLブロックでのオブジェクトの宣言

オブジェクトとADTは、CHARやNUMBERなどの組込み型が使用できるところであればどこでも使用できます。

例3-2では、employee_typ型のempオブジェクトを宣言しています。次に、オブジェクト型employee_typのコンストラクタによりオブジェクトが初期化されています。

例3-2 PL/SQLブロックでのオブジェクトの宣言

-- Requires Ex. 3-1
DECLARE
emp employee_typ; -- emp is atomically null
BEGIN
-- call the constructor for employee_typ
emp := employee_typ(315, 'Francis', 'Logan', 'FLOGAN',
'415.555.0100', '01-MAY-04', 'SA_MAN', 11000, .15, 101, 110,
address_typ('376 Mission', 'San Francisco', 'CA', '94222'));
DBMS_OUTPUT.PUT_LINE(emp.first_name || ' ' || emp.last_name); -- display details
emp.display_address();  -- call object method to display details
END;
/

PL/SQLサブプログラムの仮パラメータは、ユーザー定義型のデータ型を持つことができます。したがって、ストアド・サブプログラムにオブジェクトを渡したり、あるサブプログラムから別のサブプログラムへとオブジェクトを渡したりすることができます。次の例では、オブジェクト型employee_typが仮パラメータのデータ型を指定しています。

PROCEDURE open_acct (new_acct IN OUT employee_typ) IS ...

次の例では、オブジェクト型employee_typがファンクションの戻り型を指定しています。

FUNCTION get_acct (acct_id IN NUMBER) RETURN employee_typ IS ...

PL/SQLでの未初期化オブジェクトの処理規則

ユーザー定義型は、コレクションと同様、オブジェクト型のコンストラクタをコールしてオブジェクトを初期化するまではアトミックNULLです。つまり、オブジェクトの属性のみではなく、オブジェクト自体がNULLになります。

NULLオブジェクトを他の任意のオブジェクトと比較すると、結果は常にNULLになります。また、アトミックNULLのオブジェクトを別のオブジェクトに代入した場合は、そのオブジェクトもアトミックNULLになります(再初期化する必要があります)。同様に、値のないNULLをオブジェクトに代入した場合も、オブジェクトはアトミックNULLになります。

式の中では、未初期化オブジェクトの属性はNULLとして評価されます。IS NULL比較演算子は、未初期化オブジェクトまたはその属性に適用された場合、TRUEを返します。

NULLオブジェクト、およびNULLを持つオブジェクトについては、例2-1を参照してください。

PL/SQLでのオブジェクトの操作

この項では、PL/SQLでオブジェクトの属性とメソッドを操作する方法について説明します。

この項の内容は次のとおりです。

- ドット表記法によるオブジェクト属性へのアクセス

- オブジェクトのコンストラクタとメソッドに対するコール

- オブジェクトの更新および削除

- REF修飾子によるオブジェクトの操作

ドット表記法によるオブジェクト属性へのアクセス

属性は名前で参照します。属性にアクセスしたり属性値を変更する際には、ドット表記法を使用します。属性名を連鎖させれば、ネストされたオブジェクト型の属性にアクセスできます。

例3-3では、ドット表記を使用して例3-2と同じ出力を生成します。

例3-3 オブジェクトの属性へのアクセス

-- Requires Ex. 3-1
DECLARE
emp employee_typ;
BEGIN
emp := employee_typ(315, 'Francis', 'Logan', 'FLOGAN',
'415.555.0100', '01-MAY-04', 'SA_MAN', 11000, .15, 101, 110,
address_typ('376 Mission', 'San Francisco', 'CA', '94222'));
DBMS_OUTPUT.PUT_LINE(emp.first_name || ' '  || emp.last_name);
DBMS_OUTPUT.PUT_LINE(emp.address.street);
DBMS_OUTPUT.PUT_LINE(emp.address.city || ', '  ||emp. address.state || ' ' ||
emp.address.postal_code);
END;
/

オブジェクトのコンストラクタとメソッドに対するコール

コンストラクタは、ファンクション・コールが使用できるところであればどこからでもコールできます。例3-3および例3-4に示すように、コンストラクタはすべてのファンクションと同様、式の一部としてコールされます。

例3-4 オブジェクト表への行の挿入

-- Requires Ex. 3-1
DECLARE
emp employee_typ;
BEGIN
INSERT INTO employee_tab VALUES (employee_typ(310, 'Evers', 'Boston', 'EBOSTON',
'617.555.0100', '01-AUG-04', 'SA_REP', 9000, .15, 101, 110,
address_typ('123 Main', 'San Francisco', 'CA', '94111')) );
INSERT INTO employee_tab VALUES (employee_typ(320, 'Martha', 'Dunn', 'MDUNN',
'650.555.0150', '30-SEP-04', 'AC_MGR', 12500, 0, 101, 110,
address_typ('123 Broadway', 'Redwood City', 'CA', '94065')) );
END;
/
SELECT VALUE(e) from employee_tab e;

コンストラクタにパラメータを渡してコールした場合は、インスタンス化するオブジェクトの属性に初期値が代入されます。デフォルト・コンストラクタをコールする場合、すべての属性に値を入れるには、すべての属性に対してパラメータを指定する必要があります。定数や変数とは異なり、属性はデフォルト値を持つことができません。コンストラクタのコールには、位置表記法のかわりに名前表記法を使用することもできます。

メソッドは、パッケージ・サブプログラムと同様、ドット表記法を使用してコールします。例3-5では、オブジェクトの属性を表示するためにdisplay_addressメソッドをコールしています。オブジェクトの値を返すVALUEファンクションの使用方法に注目してください。VALUEは、相関変数を引数にとります。ここでいう相関変数とは、オブジェクト表内の行に関連付けられた行変数または表別名です。

例3-5 オブジェクト・メソッドへのアクセス

-- Requires Ex. 3-1 and Ex. 3-4
DECLARE
emp employee_typ;
BEGIN
SELECT VALUE(e) INTO emp FROM employee_tab e WHERE e.employee_id = 310;
emp.display_address();
END;
/

SQL文では、パラメータのないメソッドをコールするには空のパラメータ・リストが必要です。プロシージャ文では、コールを連鎖しないかぎり空のパラメータ・リストは任意であり、連鎖する場合は、最後のコールを除くすべてのコールにパラメータ・リストが必要です。また、2つのファンクション・コールを連鎖する場合は、1つ目のファンクションが2つ目のファンクションに渡すためのオブジェクトを戻す必要があります。

DML操作中にADTコンストラクタのかわりにPL/SQLファンクションが使用される場合は、ファンクションがDML実行の一部として複数回実行されることがあります。ファンクションを出現ごとに1回のみ実行するには、決定的ファンクションにする必要があります。

静的メソッドをコールする場合は、型のインスタンスを指定するのではなく、表記法type_name.method_nameを使用します。

サブタイプのインスタンスを使用してメソッドをコールする場合、型階層内のどのメソッドが実際に実行されるかは、宣言の内容によって異なります。サブタイプがスーパータイプから継承したメソッドをオーバーライドしている場合は、サブタイプの実装が使用されます。それ以外の場合は、スーパータイプの実装が使用されます。この機能を動的メソッド・ディスパッチといいます。

関連項目:
「動的メソッド・ディスパッチ」

オブジェクトの更新および削除

PL/SQLブロック内から、オブジェクト表の行を変更または削除できます。

例3-6 オブジェクト表の行の更新および削除

-- Requires Ex. 3-1 and 3-4
DECLARE
emp employee_typ;
BEGIN
INSERT INTO employee_tab VALUES (employee_typ(370, 'Robert', 'Myers', 'RMYERS',
'415.555.0150', '07-NOV-04', 'SA_REP', 8800, .12, 101, 110,
address_typ('540 Fillmore', 'San Francisco', 'CA', '94011')) );
UPDATE employee_tab e SET e.address.street = '1040 California'
WHERE e.employee_id = 370;
DELETE FROM employee_tab e WHERE e.employee_id = 310;
END;
/
SELECT VALUE(e) from employee_tab e;

REF修飾子によるオブジェクトの操作

REFの取得には、REFファンクションを使用できます。REFファンクションは、相関変数または別名を引数にとります。

例3-7 REF修飾子を使用したオブジェクト表内の行の更新

-- Requires Ex. 3-1, 3-4, and 3-6
DECLARE
emp         employee_typ;
emp_ref REF employee_typ;
BEGIN
SELECT REF(e) INTO emp_ref FROM employee_tab e WHERE e.employee_id = 370;
UPDATE employee_tab e
SET e.address = address_typ('8701 College', 'Oakland', 'CA', '94321')
WHERE REF(e) = emp_ref;
END;
/

REFは、変数、パラメータ、フィールドまたは属性として宣言できます。REFはSQLデータ操作文の入力変数または出力変数として使用できます。

PL/SQLでは、REFを使用してナビゲートすることはできません。たとえば、例3-8のようなREFを使用した代入は実行できません。かわりに、DEREFファンクションを使用するか、UTL_REFパッケージをコールしてオブジェクトにアクセスしてください。REFファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

例3-8 SELECT INTO文でのDEREFの使用(間違った試行)

-- Requires Ex. 3-1, 3-4, and 3-6
DECLARE
emp           employee_typ;
emp_ref   REF employee_typ;
emp_name      VARCHAR2(50);
BEGIN
SELECT REF(e) INTO emp_ref FROM employee_tab e WHERE e.employee_id = 370;
-- the following assignment raises an error, not allowed in PL/SQL  emp := DEREF(emp_ref);  --  cannot use DEREF in procedural statements
emp_name := emp.first_name || ' ' || emp.last_name;
DBMS_OUTPUT.PUT_LINE(emp_name);
END;
/

この代入により、後述のようなエラーが発生します。

not allowed in PL/SQL
-- emp_name := emp_ref.first_name || ' ' || emp_ref.last_name;
-- emp := DEREF(emp_ref); not allowed, cannot use DEREF in procedural statements

DEREFファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

継承を使用するPL/SQLでのオーバーロードの使用

オーバーロードを使用すると、サブタイプの値を仮パラメータ、つまりスーパータイプに代入できます。この機能を代入性といいます。この項では、オーバーロードのこの局面について説明します。

代入のルール

オーバーロードされたプロシージャの複数のインスタンスがプロシージャ・コールに一致する場合、次の代入ルールによって、コールされるプロシージャが判断されます。

- オーバーロードされたプロシージャのシグネチャの唯一の違いが、一部のパラメータが同じスーパータイプ・サブタイプ階層のオブジェクト・タイプである場合、最も近い一致が使用されます。最も近い一致とは、サブタイプとスーパータイプの間の継承の深さによって判断され、少なくともすべてのパラメータが他のオーバーロードされたインスタンスと同程度に近く、少なくとも1つのパラメータがより近いことをいいます。

- オーバーロードされた2つのメソッドのインスタンスが一致したが、1つ目のオーバーロードされたプロシージャにおいていくつかの引数の型が近く、2つ目のプロシージャにおいて他の引数の型が近い場合、セマンティック・エラーが発生します。

- オブジェクト型階層内でいくつかのパラメータの位置が異なり、かつ他のパラメータはデータ型が異なるために暗黙的な変換が必要になる場合も、セマンティック・エラーが発生します。

例3-9では、super_tから始まる3つのレベルを持つ型階層を作成します。パッケージには、ファンクションのオーバーロードされたインスタンスが2つ含まれ、これらのインスタンスは、型階層内の引数型の位置以外は同じです。起動では、型final_tの変数を宣言してから、オーバーロードされたファンクションをコールします。

階層内でsub_tはsuper_tよりもfinal_tに近いため、実行されるファンクションのインスタンスは、sub_tパラメータを受け入れるインスタンスです。これは、代入のルールに基づいたものです。

コールするインスタンスはコンパイル時に決定されるため、渡された引数もfinal_tであったという事実は無視されることに注意してください。宣言がv super_t := final_t(1,2,3)であれば、引数がsuper_tのオーバーロードされたファンクションがコールされます。

例3-9 PL/SQLファンクションと継承の解決

CREATE OR REPLACE 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);
/
CREATE OR REPLACE PACKAGE p IS
FUNCTION func (arg super_t) RETURN NUMBER;
FUNCTION func (arg sub_t) RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY p IS
FUNCTION func (arg super_t) RETURN NUMBER IS BEGIN RETURN 1; END;
FUNCTION func (arg sub_t) RETURN NUMBER IS BEGIN RETURN 2; END;
END;
/

DECLARE
v final_t := final_t(1,2,3);
BEGIN
DBMS_OUTPUT.PUT_LINE(p.func(v));  -- prints 2
END;
/

例3-10では、ファンクションは型階層のメンバー・ファンクションをオーバーライドしているため、コールするインスタンスは実行時に決定されます。これは、「動的メソッドのディスパッチ」で説明されている動的メソッド・ディスパッチです。

vはsuper_tのインスタンスですが、final_tの値がvに割り当てられているため、代入のルールに従ってファンクションのsub_tインスタンスがコールされます。

例3-10 PL/SQLファンクションと継承の動的解決

-- Perform the following drop commands if you created these objects in Ex. 3-9
-- DROP PACKAGE p;
-- DROP TYPE final_t;
-- DROP TYPE _sub_t;
-- DROP TYPE super_t FORCE;
CREATE OR REPLACE TYPE super_t AS OBJECT
(n NUMBER, MEMBER FUNCTION func RETURN NUMBER) NOT final;
/
CREATE OR REPLACE TYPE BODY super_t AS
MEMBER FUNCTION func RETURN NUMBER IS BEGIN RETURN 1; END; END;
/
CREATE TYPE sub_t UNDER super_t
(n2 NUMBER,
OVERRIDING MEMBER FUNCTION func RETURN NUMBER) NOT final;
/
CREATE OR REPLACE TYPE BODY sub_t AS
OVERRIDING MEMBER FUNCTION func RETURN NUMBER IS BEGIN RETURN 2; END; END;
/
CREATE OR REPLACE TYPE final_t UNDER sub_t
(n3 NUMBER);
/

DECLARE
v super_t := final_t(1,2,3);
BEGIN
DBMS_OUTPUT.PUT_LINE('answer:'|| v.func); -- prints 2
END;
/

オブジェクトでの動的SQLの使用

動的SQLは、実行時にSQL情報(表名、SQL文のフルテキスト、変数の情報など)を入力できるようにするPL/SQLの機能です。

関連項目:
『Oracle Database PL/SQL言語リファレンス』

例3-11は、動的SQLでのオブジェクトとコレクションの使用方法を示しています。この例では、最初にオブジェクト型person_typとVARRAY型hobbies_varを定義してから、これらの型を使用するパッケージteamsを定義しています。動的パッケージ・メソッドを実行するためのAUTHID CURRENT_USERが必要です。これがない場合、例3-12を実行すると、これらのメソッドでは権限不足エラーが発生します。

例3-11 オブジェクト型とコレクションに動的SQLを使用するパッケージ

CREATE OR REPLACE TYPE person_typ AS OBJECT (name VARCHAR2(25), age NUMBER);
/
CREATE TYPE hobbies_var AS VARRAY(10) OF VARCHAR2(25);
/
CREATE OR REPLACE PACKAGE teams

AUTHID CURRENT_USER AS
PROCEDURE create_table (tab_name VARCHAR2);
PROCEDURE insert_row (tab_name VARCHAR2, p person_typ, h hobbies_var);
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_typ, hobbs hobbies_var)';
END;
PROCEDURE insert_row (
tab_name VARCHAR2,
p person_typ,
h hobbies_var) 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;
v_cur refcurtyp;
p     person_typ;
h     hobbies_var;
BEGIN
OPEN v_cur FOR 'SELECT pers, hobbs FROM ' || tab_name;
LOOP
FETCH v_cur INTO p, h;
EXIT WHEN v_cur%NOTFOUND;
-- print attributes of 'p' and elements of 'h'
DBMS_OUTPUT.PUT_LINE('Name: ' || p.name || ' - Age: ' || p.age);
FOR i IN h.FIRST..h.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('Hobby(' || i || '): ' || h(i));
END LOOP;
END LOOP;
CLOSE v_cur;
END;
END;
/

匿名ブロックから、TEAMSパッケージ内のプロシージャをコールすることもできます。

例3-12 TEAMSパッケージ内のプロシージャに対するコール

DECLARE
team_name VARCHAR2(15);
BEGIN
team_name := 'Notables';
TEAMS.create_table(team_name);
TEAMS.insert_row(team_name, person_typ('John', 31),
hobbies_var('skiing', 'coin collecting', 'tennis'));
TEAMS.insert_row(team_name, person_typ('Mary', 28),
hobbies_var('golf', 'quilting', 'rock climbing', 'fencing'));
TEAMS.print_table(team_name);
END;
/

4 Oracleプログラム環境のオブジェクト・サポート

Oracleデータベースでは、SQL DDLコマンドを使用してオブジェクト型を作成し、SQL DMLコマンドを使用してオブジェクトを操作できます。そこから、多くのOracleアプリケーション・プログラミング環境およびOracleオブジェクトの組込みサポートを含むツールを使用できます。

内容は次のとおりです。

- SQLおよびオブジェクト型

- SQL Developer

- PL/SQL

- Oracle Call Interface(OCI)

- Pro*C/C++

- Oracle C++ Call Interface(OCCI)

- Oracle Objects for OLE(OO4O)

- OracleオブジェクトにアクセスするJavaツール

- XML

- オブジェクトをサポートするユーティリティ

SQLおよびオブジェクト型

Oracle SQLデータ定義言語(DDL)では、オブジェクト型に対して次のようなサポートが提供されます。

- オブジェクト型、ネストした表および配列の定義

- 権限の指定

- オブジェクト型の表の列の指定

- オブジェクト表の作成

Oracle SQL DMLでは、オブジェクト型に対して次のようなサポートが提供されます。

- オブジェクトおよびコレクションの問合せおよび更新

- REFの操作

関連項目:
Oracle SQL構文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

SQL Developer

SQL Developerは、データベース開発者およびDBAのビジュアル開発環境を提供して、Oracleオブジェクトを含むデータベース・スキーマ・オブジェクトの作成と操作、レポートの実行、豊富なグラフィカル・ユーザー・インタフェースを使用したパフォーマンスの監視および他の多くのデータベース関連タスクの実行を行います。

関連項目:
『Oracle SQL Developerユーザーズ・ガイド』

PL/SQL

オブジェクト型およびサブタイプは、組込み型が使用可能なほとんどの場所において、PL/SQLプロシージャおよびファンクションで使用できます。

PL/SQLファンクションおよびプロシージャのパラメータおよび変数には、オブジェクト型を使用できます。

PL/SQLには、オブジェクト型と対応付けられたメソッドを実装できます。これらのメソッド(ファンクションおよびプロシージャ)は、ユーザーのスキーマの一部としてサーバーに格納します。

関連項目:
PL/SQLの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

Oracle Call Interface(OCI)

OCIとは、アプリケーションがOracleデータベース内でデータおよびスキーマを操作するために使用できる、一連のCライブラリ関数のことです。OCIでは、次の項で説明するように、データベース・アクセスに従来の3GLおよびオブジェクト指向技法の両方がサポートされています。

OCIの重要なコンポーネントは、オブジェクト・キャッシュと呼ばれる作業領域を管理する一連のコールです。オブジェクト・キャッシュは、クライアント側のメモリー・ブロックで、このメモリー・ブロックにより、サーバーに対しさらにラウンドトリップを行わなくても、プログラムはオブジェクト全部を格納し、オブジェクト間をナビゲートできます。

オブジェクト・キャッシュは、それを使用するアプリケーションによって完全に制御および管理されます。Oracleサーバーは、オブジェクト・キャッシュにアクセスできません。オブジェクト・キャッシュを使用するアプリケーション・プログラムは、サーバーと一体となってデータ一貫性を保持し、同時発生する競合アクセスから作業領域を保護する必要があります。

OCIは、次の機能を備えています。

- SQLを使用して、サーバー上のオブジェクトにアクセスします。

- ポインタまたはREFを利用することによって、オブジェクト・キャッシュ内のオブジェクトにアクセスし、操作および管理します。

- Oracleの日付、文字列および数値をCのデータ型に変換します。

- オブジェクト・キャッシュのメモリー・サイズを管理します。

OCIは、オブジェクトを個々にロックできるようにして、同時実行性を改善します。これは、複雑なオブジェクト検索をサポートして、パフォーマンスを改善します。

OCI開発者は、Object Type Translatorを使用して、Oracleオブジェクト型に対応するCのデータ型を生成できます。

関連項目:
OCIでオブジェクトを使用する場合の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

OCIプログラムにおける連想アクセス

3GLプログラムは、SQL文およびPL/SQLプロシージャを実行し、リレーショナル・データベースに格納されたデータを操作します。データは、通常サーバー上で処理されるので、クライアント側にデータを転送するコストが発生しません。OCIでは、オブジェクト・データを操作するSQL文を実行するAPIを提供することによって、この結合アクセスをサポートしています。特に、OCIでは、次のことができます。

- オブジェクト・データおよびオブジェクト型スキーマ情報を操作するSQL文を実行します。

- オブジェクト、オブジェクト参照(REF)およびコレクションを、SQL文の入力変数として渡します。

- オブジェクト、REFおよびコレクションを、SQL文フェッチの出力として戻します。

- オブジェクト、REFおよびコレクションを戻すSQL文のプロパティを記述します。

- オブジェクトのパラメータまたは結果を持つPL/SQLプロシージャまたはファンクションを記述し実行します。

- 拡張されたコミットおよびロールバック関数を介して、オブジェクト機能とリレーショナル機能を並用できます。

「Pro*C/C++での連想アクセス」を参照してください。

OCIプログラムのナビゲーショナル・アクセス

オブジェクト指向のプログラミング・パラダイムでは、アプリケーションは、実社会のエンティティを、オブジェクト・グラフを形成する相互関連オブジェクトの集合としてモデル化します。オブジェクト間の関連は、参照として実装されます。アプリケーションは、いくつかのイニシャル・オブジェクトの集合から始めて、これらのイニシャル・オブジェクトの参照を使用して残りのオブジェクトにアクセスし、各オブジェクトで計算処理を実行することで、オブジェクトを処理します。OCIでは、ナビゲーショナル・アクセスとして知られる、オブジェクト参照を使用してオブジェクト間のアクセスを行うためのAPIが提供されています。特に、OCIでは、次のことができます。

- クライアント・マシン上のメモリーにオブジェクトをキャッシュします。

- オブジェクト参照を解除し、オブジェクト・キャッシュ内の対応するオブジェクトを確保します。確保されたオブジェクトは、ホスト言語表現に透過的にマップされます。

- 確保されたオブジェクトが不要になった場合、キャッシュに通知します。

- 1回のコールで、関連するオブジェクトをまとめてデータベースからクライアント・キャッシュにフェッチします。

- オブジェクトをロックします。

- キャッシュ上でオブジェクトを作成、更新および削除します。

- クライアント・キャッシュ上でオブジェクトに対して行われた変更を、データベースに反映します。

「Pro*C/C++でのナビゲーショナル・アクセス」を参照してください。

オブジェクト・キャッシュ

高パフォーマンスのオブジェクト・ナビゲーショナル・アクセスをサポートするために、OCIランタイムでは、メモリーにオブジェクトをキャッシュするためのオブジェクト・キャッシュを提供しています。オブジェクト・キャッシュは、オブジェクト・キャッシュ内のデータベース・オブジェクトへの参照(REF)をサポートし、データベース・オブジェクトは、それらの参照を介して識別(確保)されます。オブジェクト・キャッシュは、データベース・オブジェクトに対して透過的で効率的なメモリー管理を提供するため、アプリケーションは、データベース・オブジェクトがキャッシュにロードされたときに、メモリーを割り当てたり解放する必要はありません。

さらに、データベース・オブジェクトは、キャッシュにロードされた際、ホスト言語に透過的にマップされます。たとえば、C言語では、データベース・オブジェクトは対応するC構造体へマップされます。オブジェクト・キャッシュは、キャッシュ上のオブジェクトと対応するデータベース・オブジェクトとの間の整合性を保ちます。トランザクションのコミット時にキャッシュ上のオブジェクト・コピーに対して行われた変更は、データベースに自動的に反映されます。

オブジェクト・キャッシュでは、REFをオブジェクトにマップするために、高速参照表がメンテナンスされます。アプリケーションがREFを参照解除するときに、対応するオブジェクトがまだキャッシュされていない場合は、オブジェクト・キャッシュからサーバーに自動的に要求が送信され、データベースからオブジェクトがフェッチされてオブジェクト・キャッシュにロードされます。同一のREFに対するその後の参照解除は、ローカル・キャッシュ・アクセスになり、ネットワークのラウンドトリップが発生しないため、より高速になります。キャッシュ内のオブジェクトにアクセス中であることをオブジェクト・キャッシュに通知するために、アプリケーションはオブジェクトを確保し、オブジェクトの処理が終わった時点で確保解除します。オブジェクト・キャッシュは、キャッシュの各オブジェクトの確保カウントをメンテナンスします。確保カウントは、確保コール(ピン・コール)で増加し、確保解除コール(アンピン・コール)で減少します。確保カウントが0になると、アプリケーションがそのオブジェクトを必要としなくなったことを意味します。オブジェクト・キャッシュでは最低使用頻度(LRU)アルゴリズムを使用して、キャッシュのサイズが管理されます。キャッシュが最大サイズに達すると、LRUアルゴリズムによって確保カウントが0の候補オブジェクトが解放されます。

オブジェクトを操作するOCIプログラムの作成

オブジェクトを操作するOCIプログラムを作成するときは、次の一般的な手順を実行する必要があります。

1. アプリケーション・オブジェクトに対応するオブジェクト型を定義します。

2. SQL DDL文を実行して、必要なオブジェクト型をデータベースに定義します。

3. オブジェクト型をホスト言語形式で表します。
たとえば、Cプログラムでオブジェクト型のインスタンスを操作するには、それらの型をC言語形式で記述する必要があります。そのためには、オブジェクト型をC構造体で表します。OTTというツールを使用すると、オブジェクト型に対応するCの構造体を生成できます。OTTは、等価なC構造体をヘッダー・ファイル(*.h)に作成します。これらの*.hファイルを、アプリケーションを実装するC関数を含む*.cファイルにインポートします。

4. アプリケーションの*.cファイルをOCIライブラリとともにコンパイルおよびリンクすることによって、アプリケーションの実行可能ファイルを作成します。

関連項目:
OCIプログラムをオブジェクトとともに効果的に使用するためのヒントおよび技法は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

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

Cでユーザー定義コンストラクタを定義する場合は、PARAMETERS句にSELF(オプションで、SELF TDO)を指定する必要があります。C関数を入力すると、オブジェクトがマップされるすべてのC構造体の属性は、NULLに初期化されます。関数により戻される値は、ユーザー定義型のインスタンスにマップされます。例4-1に、Cでユーザー定義コンストラクタを定義する方法を示します。

例4-1 Cにおけるユーザー定義コンストラクタの定義

CREATE LIBRARY person_lib TRUSTED AS STATIC
/

CREATE TYPE person AS OBJECT
(  name VARCHAR2(30),
CONSTRUCTOR FUNCTION person(SELF IN OUT NOCOPY person, name VARCHAR2)
RETURN SELF AS RESULT);
/

CREATE TYPE BODY person IS
CONSTRUCTOR FUNCTION person(SELF IN OUT NOCOPY person, name VARCHAR2)
RETURN SELF AS RESULT
IS EXTERNAL NAME "cons_person_typ" LIBRARY person_lib WITH CONTEXT
PARAMETERS(context, SELF, name OCIString, name INDICATOR sb4);
END;/

SELFパラメータは、INパラメータと同様にマップされるため、NOT FINAL型の場合、(dvoid **)ではなく(dvoid *)にマップされます。

戻り値のTDOは、SELFのTDOと一致する必要があるため暗黙的です。戻り値はNULLになり得ないため、戻りインジケータも暗黙的です。

Pro*C/C++

Oracle Pro*C/C++プリコンパイラを使用すると、プログラマはユーザー定義データ型をCプログラムおよびC++プログラムで使用できます。

Pro*C開発者は、Object Type Translatorを使用して、Oracleオブジェクト型およびコレクションを、Pro*Cアプリケーションで使用できるCのデータ型にマップできます。

Pro*Cでは、コンパイル時のオブジェクト型とコレクションのタイプ・チェック、およびデータベースのデータ型からCのデータ型への自動型変換が行われます。

Pro*Cには、オブジェクトを作成および破棄するためのEXEC SQL構文が含まれており、次の2つを使用してサーバーにあるオブジェクトにアクセスできます。

- Pro*Cプログラム内に埋め込まれたSQL文およびPL/SQLファンクションまたはプロシージャ。

- オブジェクト・キャッシュへのインタフェース(「Oracle Call Interface (OCI)」を参照)。この場合、オブジェクトにはポインタを介してアクセスし、サーバー上で変更および更新できます。

関連項目:
Pro*Cプリコンパイラの詳細は、『Pro*C/C++プログラマーズ・ガイド』を参照してください。

Pro*C/C++での連想アクセス

連想アクセスのバックグラウンド情報については、「OCIプログラムにおける連想アクセス」を参照してください。

Pro*C/C++では、オブジェクトの連想アクセスに対して次の機能が提供されます。

- オブジェクト・キャッシュに割り当てられたオブジェクトの一時コピーのサポート

- 埋込みSQLのINSERT、UPDATE、DELETE文、またはSELECT文のWHERE句の入力ホスト変数として参照されるオブジェクトの一時コピーのサポート

- 埋込みSQLのSELECTおよびFETCH文で出力ホスト変数として参照されるオブジェクトの一時コピーのサポート

- オブジェクトの型およびスキーマ情報を取得するためにDESCRIBE文を介してオブジェクト型を参照する、ANSI動的SQL文のサポート

Pro*C/C++でのナビゲーショナル・アクセス

ナビゲーショナル・アクセスのバックグラウンド情報については、「OCIプログラムのナビゲーショナル・アクセス」を参照してください。

Pro*C/C++では、オブジェクトに対してさらにオブジェクト指向のインタフェースをサポートするために、次の機能が提供されます。

- 埋込みSQLのOBJECT DEREF文を使用した、オブジェクト・キャッシュでのオブジェクトの参照解除、確保およびロック(オプション)のサポート

- オブジェクトが更新または削除された場合、または不要になった場合に、Pro*C/C++ユーザーが埋込みSQLのOBJECT UPDATE、OBJECT DELETEおよびOBJECT RELEASE文を使用してオブジェクト・キャッシュに通知できる機能

- 埋込みSQLのOBJECT CREATE文を使用して、オブジェクト・キャッシュに新しい参照可能オブジェクトを作成するための機能

- オブジェクト・キャッシュでの変更を、埋込みSQLのOBJECT FLUSH文を使用してサーバーにフラッシュするための機能

Oracleのオブジェクト型とC言語のデータ型の間の変換

OTTによって生成されるオブジェクトのC表現では、スカラー属性に対してOCIStringやOCINumberなどの、内部詳細が非表示にされたOCI型が使用されます。コレクション型およびオブジェクト参照も、OCITable、OCIArrayおよびOCIRef型を使用して同様に表されます。この不透明な型を使用すると、これらの型の内部形式の変更が見えなくなるため、CまたはC++アプリケーションでこれらの型を使用することはお薦めしません。Pro*C/C++では、CおよびC++アプリケーションでOCI型を簡単に使用できるように、次の拡張が行われています。

- 埋込みSQLのOBJECT GET文を使用することで、オブジェクト属性を取得し暗黙的にCのデータ型に変換可能。

- 埋込みSQLのOBJECT SET文を使用することで、オブジェクト属性をCのデータ型で設定可能。

- 埋込みSQLのCOLLECTION GET文を使用することで、コレクションをホスト配列にマップ可能。さらに、コレクションがスカラー型で構成されている場合、OCI型は、暗黙的にCのデータ型に変換されます。

- 埋込みSQLのCOLLECTION SET文を使用することで、ホスト配列でコレクションの要素を更新可能。COLLECTION GET文と同様、コレクションがスカラー型で構成されている場合、Cのデータ型は、暗黙的にOCI型に変換されます。

Oracle Type Translator(OTT)

Oracle Type Translator (OTT)は、オブジェクト型に対応するCの構造体を自動的に生成するプログラムです。OTTは、Pro*CプリコンパイラおよびOCIサーバー・アクセス・パッケージをさらに使用しやすくします。

関連項目:
OTTの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』および『Pro*C/C++プログラマーズ・ガイド』を参照してください。

Oracle C++ Call Interface(OCCI)

OCCIは、C++プログラミング言語のオブジェクト指向機能、ネイティブ・クラスおよびメソッドを使用して、OracleデータベースにアクセスできるようにするC++ APIの1つです。

OCCIインタフェースはJDBCインタフェースを基に作成されているため、JDBCインタフェースのように扱いが簡単です。OCCIそのものがOCIの上に構築され、オブジェクト指向パラダイムを使用してOCIの能力およびパフォーマンスを提供します。

OCIは、Oracle Database用のC APIです。Oracleの全機能セットをサポートし、リレーショナル・データとオブジェクト・データへ効率的にアクセスしますが、特に複雑なオブジェクト・データ型を扱う場合には、問題が発生する可能性があります。オブジェクト型はCではネイティブ・サポートされていないため、Cでこれらの型をシミュレートするのは容易ではありません。OCCIは、OCIの機能に単純なオブジェクト指向インタフェースを持たせることで、この問題に取り組みます。OCI用のラッパー1組を定義して、これを行います。このような高度な抽象化を扱うことにより、開発者はOCIの基盤となる機能を使用して、非常にプログラムしやすいオブジェクト指向インタフェースを介してサーバーでオブジェクトを操作できます。

OCCIは、次の3つの機能セットに分類できます。

- 結合リレーショナル・アクセス

- 結合オブジェクト・アクセス

- ナビゲーショナル・アクセス

OCCI結合リレーショナルおよびオブジェクト・インタフェース

結合リレーショナルAPIおよびオブジェクト・クラスにより、SQLにデータベースへアクセスする機能が提供されます。これらのインタフェースを介してSQLをサーバー上で実行し、オブジェクトまたはリレーショナル・データを作成および操作し、フェッチします。アプリケーションは、次のようなサーバー上のどのデータ型にもアクセスできます。

- ラージ・オブジェクト

- オブジェクト/構造型

- 配列

- 参照

OCCIナビゲーショナル・インタフェース

ナビゲーショナル・インタフェースとは、SQLを使用せずに、C++オブジェクトの形式で表現されたオブジェクト・リレーショナル・データにシームレスにアクセスし、修正できるようにするC++インタフェースです。C++オブジェクトは透過的にアクセスし、必要に応じてデータベースに格納します。

OCCIナビゲーショナル・インタフェースを使用すると、オブジェクトを取り出し、参照によりオブジェクト間をナビゲートできます。サーバー・オブジェクトはアプリケーション・キャッシュ内部でC++クラス・インスタンスとして具体化されます。

アプリケーションはOCCIオブジェクト・ナビゲーショナル・コールを使用して、サーバー・オブジェクトに対し次の機能を実行できます。

- オブジェクトの作成、アクセス、ロック、削除およびフラッシュ

- オブジェクトの参照の取得およびオブジェクトのナビゲート

関連項目:
Oracle C++ APIを使用したアプリケーションの作成方法の詳細は、『Oracle C++ Call Interfaceプログラマーズ・ガイド』を参照してください。

Oracle Objects for OLE(OO4O)

OO4Oでは、Oracleデータベース・サーバーにあるREFのインスタンス、値インスタンス、可変長配列(VARRAY)およびネストした表へのアクセスおよび操作が完全にサポートされます。

Windowsシステム上では、OO4Oを使用して、Visual Basic、またはExcel、ActiveXおよびActive Server PagesなどのCOMプロトコルをサポートする他の環境で、オブジェクト指向データベース・プログラムを作成できます。

関連項目:
OO4OをOracleオブジェクトとともに使用する方法の詳細および使用例は、Oracle Objects for OLEの『Oracle Objects for OLE開発者ガイド』の「サーバー・オブジェクト」の章を参照してください

図4-1に、OO4Oにおけるすべての型の値インスタンスの抑制階層を示します。

図4-1 サポートされているOracleデータ型

これらの型のインスタンスは、データベースからフェッチできるか、またはSQL文および(ストアド・プロシージャおよびファンクションを含む)PL/SQLブロックに対する入力変数または出力変数として渡すことができます。すべてのインスタンスは、属性の動的アクセスおよび操作用のメソッドを提供する、COMオートメーション・インタフェースにマップされます。このインタフェースは、次のものから取得できます。

- dynasetのOraFieldオブジェクトの値プロパティ

- SQL文またはPL/SQLブロックで入力または出力パラメータとして使用されるOraParameterオブジェクトの値プロパティ

- オブジェクトの属性(REF)

- コレクションの要素(VARRAYまたはネストした表)

Visual Basicでのオブジェクトの表現形式(OraObject)

OraObjectインタフェースは、Oracle埋込みオブジェクトまたは値インスタンスの表現形式です。これには、値インスタンスの個々の属性にアクセスおよび操作(更新および挿入)するためのコレクション・インタフェース(OraAttributes)が含まれます。OraAttributesコレクション・インタフェースの個々の属性には、添字または属性の名前を使用して、アクセスできます。

次のVisual Basicの例では、person_tab表のAddressオブジェクトの属性にアクセスする方法を示します。

Dim Address OraObject
Set Person =
OraDatabase.CreateDynaset("select * from person_tab", 0&)
Set Address = Person.Fields("Addr").Value
Msgbox Address.Zip
Msgbox.Address.City

Visual BasicでのREFの表現形式(OraRef)

OraRefインタフェースは、Oracleオブジェクト参照(REF)を表すと同時に、クライアント・アプリケーションの参照可能なオブジェクトを表します。このオブジェクト属性には、OraObjectインタフェースによって表されるオブジェクトの属性と同じ方法でアクセスできます。OraRefは、COMでの抑制メカニズムを介して、OraObjectインタフェースから導出されます。REFオブジェクトは、dynasetなど導出元となるコンテキストからは独立して、更新および削除できます。OraRefインタフェースでは、OCIの複合オブジェクト検索機能(COR)を使用して、オブジェクト間の関連をたどる機能のカプセル化も行います。

関連項目:
OCIプログラムをオブジェクトとともに効果的に使用するためのヒントおよび技法は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

Visual BasicでのVARRAYおよびネストした表の表現形式(OraCollection)

OraCollectionインタフェースでは、OO4OにおいてOracleコレクション型、つまり可変長配列(VARRAY)およびネストした表にアクセスおよび操作するためのメソッドが提供されます。コレクションに含まれる要素には、添字でアクセスできます。

次のVisual Basicの例では、department表のEnameListオブジェクトの属性にアクセスする方法を示します。

Dim EnameList OraCollection
Set Person =
OraDatabase.CreateDynaset("select * from department", 0&)
Set EnameList = Department.Fields("Enames").Value
'The following loop accesses all elements of
'the EnameList VArray
For I=1 to I=EnameList.Size
Msgbox EnameList(I)
Next I

OracleオブジェクトにアクセスするJavaツール

Javaは、開発者に簡単で効率的でポータブルかつ安全なアプリケーション開発プラットフォームを提供する強力な最新のオブジェクト指向言語として登場しました。Oracleでは、Oracleオブジェクト機能をJavaと統合する様々な方法を提供しています。これらのインタフェースにより、JavaからSQLデータにアクセスできるようになるのみでなく、Javaオブジェクトの永続データベース記憶域が得られます。

- Oracleオブジェクト・データへのJDBCアクセス

- Oracleオブジェクト・データへのSQLJアクセス

- データ・マッピング方法の選択

- JPublisherを使用したJDBCおよびSQLJプログラム用Javaクラスの作成

- Javaオブジェクトの記憶域

- Javaでのユーザー定義コンストラクタの定義

- JDeveloper

Oracleオブジェクト・データへのJDBCアクセス

JDBCは、Oracleサーバーに接続するためのJavaインタフェースの集合です。Oracleでは、オブジェクトとJDBCの間の緊密な統合が提供されます。SQL型はJavaクラスにマップでき、このマップ方法について、かなりの柔軟性が提供されています。

Oracle JDBC:

- 動的SQLを使用して、Javaプログラム内でオブジェクト型およびコレクション型(データベースで定義)にアクセスできます。

- デフォルトまたはカスタマイズ可能なマッピングを使用して、データベースで定義されたデータ型をJavaクラスに変換します。

JDBC 2.0では、ユーザー定義型(オブジェクト型)などのオブジェクト・リレーショナル構造がサポートされています。JDBCは、Oracleオブジェクトを特定のJavaクラスのインスタンスとして具体化します。JDBCを使用してOracleオブジェクトにアクセスするには、OracleオブジェクトについてJavaクラスを作成し、これらのクラスを移入する必要があります。たとえば、次のような処理を行うことができます。

- JDBCにオブジェクトをSTRUCTとして具体化させます。この場合、JDBCは属性のクラスを作成し、作成したクラスを移入します。

- OracleオブジェクトとJavaクラスの間のマッピングを手動で指定します。つまり、Javaクラスをオブジェクト・データ用にカスタマイズします。この後、ドライバはカスタマイズされた指定のJavaクラスを移入し、これがJavaクラスに対する一連の制約となります。これらの制約に従うために、クラスをSQLDataインタフェースまたはORADataインタフェースのどちらにあわせて定義するかを選択できます。

関連項目:
Oracle JDBCドライバの詳細は、『Oracle Database JDBC開発者ガイドおよびリファレンス』を参照してください。

Oracleオブジェクト・データへのSQLJアクセス

SQLJでは、Javaコードに埋め込んだSQL文を使用して、サーバー・オブジェクトへアクセスできます。

- Javaプログラムでオブジェクト型を使用可能です。

- JPublisherを使用して、オブジェクト型およびコレクション型を、アプリケーションで使用できるJavaクラスにマップします。

- SQL文のオブジェクト型およびコレクション型は、コンパイル時にチェックされます。

関連項目:
SQLJの詳細は、『Oracle Database Java開発者ガイド』を参照してください

データ・マッピング方法の選択

Oracle SQLJでは、イテレータまたはホスト式で使用するオブジェクト型、参照型(REF)およびコレクション型(VARRAYおよびネストした表)の強力な型指定または緩い型指定のJava表現がサポートされます。

強力な型指定の表現では、特定のオブジェクト型、REF型またはコレクション型に対応するカスタムJavaクラスを使用し、インタフェースoracle.sql.ORADataを実装する必要があります。Oracle JPublisherユーティリティでは、そのようなカスタムJavaクラスを自動的に生成します。

緩い型指定の表現では、クラスoracle.sql.STRUCT(オブジェクト用)、oracle.sql.REF(参照用)またはoracle.sql.ARRAY(コレクション用)を使用します。

JPublisher

Oracle JPublisherはユーティリティで、次のユーザー定義データベース・エンティティをユーザーのJavaプログラムで表すJavaクラスを生成します。

- データベース・オブジェクト・タイプ

- データベース参照(REF)型

- データベース・コレクション型(VARRAYまたはネストした表)

- PL/SQLパッケージ

JPublisherにより、強力な型指定パラダイムで、データベース・オブジェクト型、参照型およびコレクション型(VARRAYまたはネストした表)をJavaクラスに対してマップする操作を指定し、カスタマイズできます。

関連項目:
『Oracle Database JPublisherユーザーズ・ガイド』

JPublisherを使用したJDBCおよびSQLJプログラム用Javaクラスの作成

Oracleでは、オブジェクト型、参照型およびコレクション型をJavaクラスにマップすることで、強力な型指定によるすべての利点を得ることができます。たとえば、次のような処理を行うことができます。

- Oracle JPublisherを使用してカスタムJavaクラスを自動的に生成し、それらのクラスを変更なしで使用します。

- JPublisherによって生成されたクラスをサブクラス化し、独自の専用Javaクラスを作成します。

- 『Oracle Database JPublisherユーザーズ・ガイド』に記述されている要件をクラスが満たす場合は、JPublisherを使用せず、カスタムJavaクラスを手動でコーディングできます。

生成されたクラスが十分な機能を果さない場合は、JPublisherおよびサブクラスを使用することをお薦めします。

ユーザー定義のオブジェクト型に対してJPublisherで生成される内容

オブジェクト型に対してJPublisherを実行する場合、次のものが自動的に作成されます。

- ユーザーのOracleオブジェクト型に対応する型定義として動作するカスタム・オブジェクト・クラス
このクラスには、各属性に対する取得メソッドおよび設定メソッドが含まれます。メソッド名は、属性xxxの場合は、getXxx()およびsetXxx()の形式をとります。

また、オプションで、サーバーで実行されるOracleオブジェクト・メソッドを起動するラッパー・メソッドをクラスに作成するように指定できます。

- ユーザーのOracleオブジェクト型に対するオブジェクト参照用のカスタム・リファレンス・クラス
このクラスには、ユーザーのカスタム・オブジェクト・クラスのインスタンスを戻すgetValue()メソッドおよびデータベースのオブジェクト値を更新するsetValue()メソッドが含まれます。これらのメソッドは、入力としてカスタム・オブジェクト・クラスのインスタンスをとります。

コレクション型に対してJPublisherを実行する場合、次のものが自動的に作成されます。

- ユーザーのOracleコレクション型に対応する型定義として動作するカスタム・コレクション・クラス
このクラスには、コレクション全体を取得または更新する、オーバーロード型のgetArray()メソッドおよびsetArray()メソッド、コレクションの個々の要素を取得または更新するgetElement()メソッドおよびsetElement()メソッド、その他のユーティリティ・メソッドが含まれます。

これらのどのカテゴリでも、JPublisherが生成するカスタムJavaクラスでは、ORADataインタフェースおよびgetFactory()メソッドが実装されます。

関連項目:
JPublisherの詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。

Javaオブジェクトの記憶域

JPublisherを使用すると、既存のSQL型にマップするJavaクラスを作成できます。このようにJavaクラスを作成した後、JDBCによりJavaアプリケーションからSQL型にアクセスできるようになります。

この逆を実行することもできます。つまり、既存のJavaクラスにマップするSQL型を作成できます。これにより、Javaオブジェクト用の永続ストレージが用意できます。これらのSQL型を、Java言語のSQL型またはSQLJオブジェクト型といいます。これらは、オブジェクト、属性、列、またはオブジェクト表の行の型として使用できます。オブジェクト参照または外部キーを介して、これらのタイプのオブジェクト(Javaオブジェクト)に対して、ナビゲーショナル・アクセスを行ったり、SQLからこれらのオブジェクトの問合せや操作ができます。

他のユーザー定義型と同様に、SQLJ型もCREATE TYPE文を使用して作成します。SQLJ型の場合、次の2つの特別な要素がCREATE TYPE文に追加されます。

- それぞれのSQLJ属性とメソッドに対応するJavaの属性とメソッド、およびSQLJ型そのものに対応するJavaクラスの識別に使用するEXTERNAL NAME句。

- サーバーに対してSQLJ型をどのように表現するかを指定するためのUSING句。USING句は、SQLJ型およびストレージの種類を取得するために使用するインタフェースを指定します。

次に例を示します。

例4-2 SQL型からJavaクラスへのマッピング

-- Mapping SQL Types to Java Classes example, not sample schema
CREATE TYPE full_address AS OBJECT (a NUMBER);
/

CREATE OR REPLACE TYPE person_t AS OBJECT
EXTERNAL NAME 'Person' LANGUAGE JAVA
USING SQLData (
ss_no NUMBER (9) EXTERNAL NAME 'socialSecurityNo',
name varchar(100) EXTERNAL NAME 'name',
address full_address EXTERNAL NAME 'addrs',
birth_date date EXTERNAL NAME 'birthDate',
MEMBER FUNCTION age  RETURN NUMBER EXTERNAL NAME 'age () return int',
MEMBER FUNCTION addressf RETURN full_address
EXTERNAL NAME 'get_address () return long_address',
STATIC function createf RETURN person_t EXTERNAL NAME 'create ()
return Person',
STATIC function createf (name VARCHAR2, addrs full_address, bDate DATE)
RETURN person_t EXTERNAL NAME 'create (java.lang.String, Long_address,
oracle.sql.date) return Person',
ORDER member FUNCTION compare (in_person person_t) RETURN NUMBER
EXTERNAL NAME 'isSame (Person) return int')
/

SQLJ型は、対応するJavaクラスを型の本体として使用します。ただし、SQLでは、通常のオブジェクト型のように、型のメソッドの実装を格納する目的で型の本体は指定しません。

サーバーに対するSQLJ型の表現

SQLJ型をサーバーに対してどのように表現し、格納するかは、対応するJavaクラスが実装するインタフェースによって決まります。現在、Oracleでは、SQLDataまたはORADataインタフェースを実装するJavaクラスに対してのみ、SQLJ型の表現がサポートされます。サーバーに対して、これらは表現され、SQLを介してアクセス可能になります。java.io.Serializableインタフェースを実装するJavaクラスの表現は、現在サポートされていません。

SQL表現では、型の属性は、通常のオブジェクト型の属性と同様に、列に格納されます。この表現の場合、オブジェクトはSQL文を使用してアクセスおよび操作しますが、オブジェクト・データの整合性を確保するために、トリガーおよび制約が使用できるため、属性はすべてパブリックです。

SQL表現の場合、USING句によりSQLDataまたはORADataのいずれかを指定する必要があります。また、これらのインタフェースの1つを対応するJavaクラスにより実装する必要があります。属性用のEXTERNAL NAME句は任意で使用してください。

SQLJオブジェクト型の作成

SQLJ型を作成し、Javaへのマッピングを指定するSQL文は、デプロイメント・ディスクリプタと呼ばれるファイルの中に収められます。関連するSQL制約および権限も、このファイルに指定されます。型は、ファイルが実行されるときに作成されます。

次に、JavaタイプおよびJavaクラスのSQLバージョンを作成するプロセスの概要を示します。

1. Javaタイプを設計します。

2. Javaクラスを作成します。

3. SQLJオブジェクト型の文を作成します。

4. JARファイルを作成します。これは、必要なクラスがすべて入っている1つのファイルです。

5. loadjavaユーティリティを使用して、JARファイルに定義されているJavaクラスをインストールします。

6. 文を実行して、SQLJオブジェクト型を作成します。

マッピングに関するその他の注意

JavaクラスをSQL型にマップする際、次の点を考慮してください。

- SQLJ静的ファンクションは、Javaクラスのユーザー定義コンストラクタにマップできます。このファンクションの戻り値は、ファンクションをローカルに定義したユーザー定義型をとります。

- Javaの静的変数は、対応する静的変数(EXTERNAL NAMEで識別)の値を返すSQLJ静的メソッドにマップします。SQLDataまたはORAData表現の場合、属性用のEXTERNAL NAME句は任意で使用します。

- SQL表現のSQLJ型のどの属性も、Javaフィールドにマップする必要があります。ただし、必ずしもすべてのJavaフィールドを、対応するSQLJ属性にマップする必要はありません。マッピングではJavaフィールドが省略できます。

- クラスは省略できます。SQLJ型をルート・クラスにマップせず、またスーパークラスを介在させずに、SQLJ型をJavaクラス階層内の非ルート・クラスにマップできます。これにより、スーパークラスから継承した属性およびメソッドを含んだまま、スーパークラスを非表示にできます。
ただし、クラス階層内のノード間の構造対応関係およびSQLJ型階層に存在するノード間の構造対応関係はそのまま保つ必要があります。つまり、継承により関連付け、2つのSQL型であるs_Aおよびs_Bにマップする2つのJavaクラスj_Aおよびj_Bの場合、j_Aからj_Bへの継承パスのそれぞれのノードについて、s_Aからs_Bへの継承パスに対応するノードが1つ存在する必要があります。

- 前述の制限に違反しないかぎり、Javaクラスを複数のSQLJ型にマップできます。つまり、同一のJavaクラスにマップされた2つのSQLJ型は、共通するスーパータイプの祖先クラスを持てないということです。

- すべてのJavaクラスをSQLJ型にマップしなければ、SQLJオブジェクト型の属性を、マップされていないJavaクラスのオブジェクトに設定することが可能です。特に、継承階層において属性がマップされたクラスの上位または下位で発生するクラスの場合、これに該当します。オブジェクトのクラスが、属性の型/クラスのスーパークラスの場合は、エラーとなります。オブジェクトのクラスが、属性の型/クラスのサブクラスであれば、SQLマッピングが存在するオブジェクトの階層の最も狭い意味での型に、オブジェクトがマップされます。

関連項目:
オブジェクト・マッピングのJPublisherでの使用例は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。

SQLJ型の進化

ALTER TYPE文を使用すると、属性またはメソッドの追加、削除などを行うことにより、型を進化させられます。

SQLJ型を進化させる場合は、クラスと型間のマッピングを確認するために、特別な検証を行います。クラスと進化させた型が一致した場合は、有効な型であると表示されます。一致しない場合は、検証待ちと表示されます。

検証待ちという表示は、無効という表示と同じではありません。検証待ちの型は、たとえばALTER TYPEおよびGRANT文を使用して、操作を継続できます。

SQL表現を持つ型が、検証待ちと表示されても、メソッド起動を必要としないDMLまたはSELECT文を使用して、この型の表にアクセスできます。

ただし、シリアル化可能な表現を持ち、検証待ちと表示された型の表に対しては、DMLやSELECT文は実行できません。シリアル化可能な型のデータに対しては、メソッド起動を介したナビゲーショナル・アクセスのみ許可されます。検証待ちの型の場合は、このタイプのアクセスはできません。ただし、検証に合格するまで型をさらに進化させることは可能です。

「型進化」を参照してください。

制約

SQL表現を持つSQLJ型の場合、通常のオブジェクト型の場合と同じ制約を定義できます。

制約を定義する対象は、型ではなく表で、列レベルで定義します。SQL表現を持つSQLJ型についてサポートされている制約は、次のとおりです。

- 一意制約

- 主キー

- CHECK制約

- 属性についてのNOT NULL制約

- 参照制約

SQL表現を持つSQLJ型の場合は、列の代入性についてのIS OF type制約もサポートされます。「代入性の制約」を参照してください。

SQLJオブジェクトの問合せ

SQLJ型に対しては、通常のSQLオブジェクト型と同様に問合せを行うことができます。SELECT文でコールされたメソッドで、属性値を変更することは避けてください。

Javaオブジェクトの挿入

SQLJ型の列が入っている表に、行を挿入するには、この型のコンストラクタ・ファンクションをコールし、この型のJavaオブジェクトを作成する必要があります。

システムが生成する暗黙的なコンストラクタを使用するか、またはJavaクラスのユーザー定義コンストラクタにマップする静的ファンクションを定義してください。

SQLJオブジェクトの更新

UPDATE文を使用して、1つ以上の属性の値を変更するか、または属性を更新しSELFを戻すメソッド(つまり、変更を行ったうえでオブジェクトそのものを戻すメソッド)を起動すると、SQLJオブジェクトを更新できます。

raise()が、指定された分のみsalaryフィールド/属性を増加し、SELFを戻すメンバー・ファンクションである場合について考えてみます。次の文により、オブジェクト表employee_objtabに含まれているすべての従業員に1000分の増額が与えられます。

UPDATE employee_objtab SET c=c.raise(1000);

SQLJ型の列は、通常のオブジェクト型と同じ構文を使用して、NULLに設定するか、または別の列に設定できます。たとえば、次の文により、列cに列dが割り当てられます。

UPDATE employee_reltab SET c=d;

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

Javaでユーザー定義コンストラクタを実装する場合、実装ルーチンとして提供される文字列は、静的ファンクションに対応する必要があります。ファンクションの戻り型には、SQL型にマップされるJava型を指定します。

例4-3に、Javaで実装されたユーザー定義コンストラクタを伴う型宣言の例を示します。

例4-3 Javaにおけるユーザー定義コンストラクタの定義

-- Defining a User-Defined Constructor in Java example, not sample schema
CREATE TYPE person1_typ AS OBJECT
EXTERNAL NAME 'pkg1.J_Person' LANGUAGE JAVA
USING SQLData(
name VARCHAR2(30),
age NUMBER,
CONSTRUCTOR FUNCTION person1_typ(SELF IN OUT NOCOPY person1_typ, name VARCHAR2,
age NUMBER) RETURN SELF AS RESULT
AS LANGUAGE JAVA
NAME 'pkg1.J_Person.J_Person(java.lang.String, int) return J_Person')
/

DROP TYPE person1_typ FORCE;
DROP TYPE person_t FORCE;
DROP TYPE full_address FORCE;
DROP TYPE person FORCE;
DROP LIBRARY person_lib;
SPOOL OFF
COMMIT;

JDeveloper

Oracle JDeveloperは、Oracle Application ServerおよびOracle Databaseと緊密に統合された複数層のJavaアプリケーションの作成を目的としたフル機能のクロスプラットフォームの統合開発環境です。

Oracle JDeveloperにより、Javaクライアント・アプリケーション、動的HTMLアプリケーション、Webおよびアプリケーション・サーバー・コンポーネント、JavaBeanコンポーネントおよび業界標準モデルに基づいたデータベース・ストアド・プロシージャの開発、デバッグおよびデプロイができます。

JDeveloperは、ADFおよびTopLinkの統合開発環境でもあります。

アプリケーション開発フレームワーク(ADF)

ADFは、スケーラブルなエンタープライズJava EEアプリケーションを作成するフレームワークです。開発者は、ADFを使用して、アプリケーション・データが他のスキーマ・オブジェクトとともにOracleオブジェクト表に保存されるアプリケーションを作成できます。

TopLink

TopLinkは、Javaオブジェクトをデータベースを含む様々な永続性テクノロジにマップするフレームワークで、Oracleオブジェクトを利用するアプリケーションを作成する機能を提供します。

XML

XMLTypeビューは、既存のリレーショナル・データおよびオブジェクト・リレーショナル・データをXML形式でラップします。これらのビューは、オブジェクト・ビューと類似しています。XMLTypeビューの各行は、XMLTypeインスタンスに対応します。ビュー内の各行を一意に識別するためのオブジェクト識別子は、XMLType値に対してextract()などの式を使用して作成できます。

関連項目:
XMLとOracleオブジェクトの使用方法の詳細および使用例は、『Oracle XML DB開発者ガイド』を参照してください。

オブジェクトをサポートするユーティリティ

この項では、Oracleオブジェクトのサポートを提供する複数のOracleユーティリティについて説明します。

この項の内容は次のとおりです。

- オブジェクト型のインポート/エクスポート

- SQL*Loader

オブジェクト型のインポート/エクスポート

エクスポート・ユーティリティおよびインポート・ユーティリティは、Oracleデータベースへ、またはOracleデータベースから、データを移動します。また、データのバックアップまたはアーカイブ、およびOracle RDBMSの異なるリリースへの移行に役立ちます。

エクスポートおよびインポートは、オブジェクト型をサポートします。エクスポートは、オブジェクト型定義および関連するすべてのデータをダンプ・ファイルに書き込みます。インポートは、ダンプ・ファイルからこれらの項目を再作成します。

オブジェクト表をインポートする場合、デフォルトでOIDが維持されます。

関連項目:
インポートおよびエクスポート・ユーティリティの使用方法は、『Oracle Databaseユーティリティ』を参照してください。

タイプ

導出型の定義文はエクスポートされます。インポート時、スーパータイプ定義のインポートが完了する前に、サブタイプを作成できます。この場合、サブタイプを作成するとコンパイル・エラーが発生しますが、無視してください。型のスーパータイプが作成された後、型の再検証が行われます。

オブジェクト・ビューの階層

ビュー階層に属するすべてのビューのビュー定義はエクスポートされます。

SQL*Loader

SQL*Loaderユーティリティは、外部ファイルのデータを、Oracle Database内の表に移動します。これらのファイルには、INTEGER、CHAR、DATEなど基本的なスカラー・データ型や、行オブジェクトや列オブジェクト(オブジェクト、コレクションまたはREF属性を持つオブジェクトを含む)、コレクション、LOBなど複雑なユーザー定義データ型で構成されるデータが含まれる可能性があります。現在、SQL*Loaderはシングルレベル・コレクションのみをサポートしています。マルチレベル・コレクション(他のコレクションが要素になっているか、他のコレクションが入っているコレクション)のロードに、SQL*Loaderは使用できません。SQL*Loaderは、SQL*Loader DDL文が入っている制御ファイルを使用して、データ・ファイルのフォーマット、内容および位置を記述します。

SQL*Loaderがデータをロードする方法は、2通りあります。

- 従来型パス・ロード: SQL INSERT文およびバインド配列バッファを使用して、データをデータベース表にロードします。

- ダイレクト・パス・ロード: ダイレクト・パス・ロードAPIを使用して、SQL*Loaderクライアントのかわりに、データ・ブロックを直接データベースに書き込みます。
ダイレクト・パス・ロードはSQLインタフェースを使用しないので、関連するSQL文の処理時にオーバーヘッドが発生しません。したがって、ダイレクト・パス・ロードからは従来型パス・ロードよりも優れたパフォーマンスが通常得られます。

どちらの方法も、サポート対象となっているオブジェクトおよびコレクション・データ型のデータのロードに使用できます。

関連項目:
SQL*Loaderの使用方法は、『Oracle Databaseユーティリティ』を参照してください。

5 コレクション・データ型のサポート

この章では、コレクション型(VARRAYおよびネストした表)を作成して管理する方法について説明します。

関連項目:
コレクションの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

内容は次のとおりです。

- コレクション・データ型

- マルチレベル・コレクション型

- コレクション・データ型の操作

- Oracleオブジェクトを持つ表のパーティション化

コレクション・データ型

Oracleでは、VARRAYとネストした表のコレクション・データ型がサポートされます。

- VARRAYとは、順序付けられた要素の集合です。

- ネストした表には、要素をいくつでも入れることができます。順序付けはされません。

一定数の項目のみ格納する必要がある場合、順序に従って要素をループする必要がある場合、またはコレクション全体を1つの値として取り出して操作する必要がある場合は、VARRAYを使用してください。

コレクションについての問合せを効率的に実行する必要がある場合は、任意の数の要素を扱うか、大量の挿入、更新または削除を行ってから、ネストした表を使用してください。「コレクションの設計上の考慮点」を参照してください。

この項の内容は次のとおりです。

- コレクション型の作成

- コレクション型の作成

- VARRAYまたはネストした表のインスタンスの作成

- コレクションのコンストラクタ・メソッド

- VARRAY

- ネストした表

- VARRAYおよびネストした表要素のサイズおよび精度の増加

- VARRAYの制限サイズの増加

- LOB参照が含まれているVARRAYの作成

コレクション型の作成

この項では、ネストした表型の作成方法を示します。VARRAY型の作成については、「VARRAY」で説明します。

例5-1では、person_typオブジェクトと、person_typオブジェクトのネストした表型としてのpeople_typを作成します。どちらも、この章の後続の例で使用します。

例5-1 後続の例で使用するCREATE TYPE person_typ

CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) );
/

CREATE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) IS
BEGIN
-- use the put_line procedure of the DBMS_OUTPUT package to display details
DBMS_OUTPUT.put_line(TO_CHAR(idno) || ' - '  || name || ' - '  || phone);
END;
END;
/

CREATE TYPE people_typ AS TABLE OF person_typ; -- nested table type
/

VARRAYまたはネストした表のインスタンスの作成

コレクション型のインスタンスは、他のオブジェクト型のインスタンスを作成する場合と同じ方法、つまり型のコンストラクタ・メソッドをコールして作成します。コンストラクタ・メソッドの名前は、型の名前です。コレクションの各要素は、次のように、カンマで区切ったメソッドの引数のリストとして指定します。

( person_typ(1, 'John Smith', '1-650-555-0135'),

空のリストでコンストラクタ・メソッドをコールすると、その型の空のコレクションが作成されます。空のコレクションとは、偶然に空になっている実際のコレクションで、NULLコレクションとは異なる点に注意してください。ネストした表の使用方法の詳細は、「ネストした表の設計上の考慮点」を参照してください。

コレクションのコンストラクタ・メソッド

SQL文のコンストラクタ・メソッドを使用して、ネストした表に値を挿入できます。

例5-2では、最初にネストした表型people_typのインスタンスが含まれる表(people_column)を作成し、次にSQL文でコンストラクタ・メソッドを使用して値をpeople_typに挿入する方法を示します。この例では、コンストラクタ・メソッドのリテラル起動を使用します。

例5-2 ネストした表に値を挿入するためのコンストラクタ・メソッドの使用

-- Requires Ex. 5-1
CREATE TABLE people_tab (
group_no NUMBER,
people_column people_typ )  -- an instance of nested table
NESTED TABLE people_column STORE AS people_column_nt; -- storage table for NT

INSERT INTO people_tab VALUES (
100,
people_typ( person_typ(1, 'John Smith', '1-650-555-0135'),
person_typ(2, 'Diane Smith', NULL)));

表の列をオブジェクト型またはコレクション型として宣言する場合、DEFAULT句を含めることができます。明示的に列に値を指定しない場合には、このDEFAULT句で指定した値が使用されます。DEFAULT句には、そのオブジェクトまたはコレクションのコンストラクタ・メソッドのリテラル起動を含める必要があります。

例5-3に、コンストラクタ・メソッドのリテラル起動を使用してオブジェクトperson_typおよびネストした表people_typのデフォルトを指定する方法を示します。

例5-3 DEFAULT句を使用したdepartment_persons表の作成

-- requires Ex. 5-1
CREATE TABLE department_persons (
dept_no    NUMBER PRIMARY KEY,
dept_name  CHAR(20),
dept_mgr   person_typ DEFAULT person_typ(10,'John Doe',NULL),
dept_emps  people_typ DEFAULT people_typ() ) -- instance of nested table type
NESTED TABLE dept_emps STORE AS dept_emps_tab;

INSERT INTO department_persons VALUES
( 101, 'Physical Sciences', person_typ(65,'Vrinda Mills', '1-650-555-0125'),
people_typ( person_typ(1, 'John Smith', '1-650-555-0135'),
person_typ(2, 'Diane Smith', NULL) ) );
INSERT INTO department_persons VALUES
( 104, 'Life Sciences', person_typ(70,'James Hall', '1-415-555-0101'),
people_typ() ); -- an empty people_typ table

people_typ()は、空のネストした表people_typのコンストラクタ・メソッドのリテラル起動であることに注意してください。

例5-16および例5-17に示すように、department_persons表は2つの方法で問い合せることができます。

VARRAY

VARRAYとは、順序付けられたデータ要素の集合です。任意のVARRAYのすべての要素は、同じデータ型または宣言されたデータ型のサブタイプの要素です。各要素は、索引を持ちますが、これは配列における要素の位置に対応する番号です。索引番号は、特定の要素にアクセスするために使用されます。

VARRAYを定義するときは、ここに格納できる要素の最大数を指定しますが、この値は後で変更できます。配列における要素の数は、配列のサイズです。

次の文では、それぞれがVARCHAR2(80)データ型の最大10個の要素を持つ配列型email_list_arrを作成します。

CREATE TYPE email_list_arr AS VARRAY(10) OF VARCHAR2(80);
/

例5-4では、オブジェクト型の配列としてのVARRAY型を作成します。phone_varray_typ VARRAY型は、dept_phone_list表の列のデータ型として使用されます。このINSERT文は、VARRAY phone_varray_typとオブジェクトphone_typのコンストラクタを起動してphone_varray_typに値を挿入する方法を示しています。

例5-4 VARRAYデータ型の作成と移入

CREATE TYPE phone_typ AS OBJECT (
country_code   VARCHAR2(2),
area_code      VARCHAR2(3),
ph_number      VARCHAR2(7));
/
CREATE TYPE phone_varray_typ AS VARRAY(5) OF phone_typ;
/
CREATE TABLE dept_phone_list (
dept_no NUMBER(5),
phone_list phone_varray_typ);

INSERT INTO dept_phone_list VALUES (
100,
phone_varray_typ( phone_typ ('01', '650', '5550123'),
phone_typ ('01', '650', '5550148'),
phone_typ ('01', '650', '5550192')));

配列型を作成しても、SQLオブジェクト型と同様、領域は割り当てらません。データ型が定義され、その用途は次のとおりです。

- リレーショナル表の列のデータ型。

- オブジェクト型属性。

- PL/SQL変数、パラメータまたはファンクション戻り値の型。

通常、VARRAYはインラインに、つまり、その行にある他のデータと同じ表領域に格納されます。サイズが十分であれば、BLOBとして格納されます。「VARRAYの記憶域上の考慮点」を参照してください。

PL/SQLまたはビュー問合せなど、手順上の目的でXMLTypeのVARRAY型またはLOB型を作成できます。ただし、これらの型のVARRAYのデータベース記憶域はサポートされていません。このため、XMLTypeのVARRAY型またはLOB型のオブジェクト表またはオブジェクト型列は作成できません。

関連項目:
CREATE TABLE文のSTORE AS LOB句の詳細および例は、『Oracle Database SQL言語リファレンス』を参照してください。

ネストした表

ネストした表は順序を設定していないデータ要素のセットで、すべて同じデータ型です。表の定義では最大値は指定されず、要素の順序は維持されません。通常の表を扱う場合と同様に、TABLE式を使用して、ネストした表でも選択、挿入、削除および更新の操作ができます。

ネストした表は単一列として表示できます。ネストした表の列がオブジェクト型であれば、オブジェクト型の各属性に対して列を持つ複数列表としても、表を表示できます。

ネストした表型を宣言するには、CREATE TYPE ... AS TABLE OF文を使用します。次に例を示します。

CREATE TYPE people_typ AS TABLE OF person_typ;

表型の定義では、領域は割り当てられません。ここでは次のような型を定義します。

- リレーショナル表の列のデータ型。

- オブジェクト型属性。

- PL/SQL変数、パラメータまたはファンクション戻り型。

ネストした表の要素の格納

ネストした表の要素は、実際には個別の記憶表に格納されます。

Oracleでは、ネストした表のデータは、リレーショナル表の列またはオブジェクト表の属性である両方のネストした表型に対応するオブジェクト表に関連付けられた1つの記憶表に格納されます。この記憶表には、ネストした表の各要素が属する親表の行やオブジェクトを識別する列が含まれています。図9-2「ネストした表の記憶域」を参照してください。

NESTED TABLE..STORE AS句は、ネストした表の記憶域名を指定します。記憶域名は、ネストした表に索引を作成するときに使用します。

例5-5では、ネストした表を作成して移入し、例5-1で定義したオブジェクトperson_typおよびネストした表people_typを使用して、ネストした表記憶域を指定します。

例5-5 単純なネストした表の作成および移入

-- Requires 5-1
CREATE TABLE students (
graduation DATE,
math_majors people_typ, -- nested tables (empty)
chem_majors people_typ,
physics_majors people_typ)
NESTED TABLE math_majors STORE AS math_majors_nt  -- storage tables
NESTED TABLE chem_majors STORE AS chem_majors_nt
NESTED TABLE physics_majors STORE AS physics_majors_nt;

CREATE INDEX math_idno_idx ON math_majors_nt(idno);
CREATE INDEX chem_idno_idx ON chem_majors_nt(idno);
CREATE INDEX physics_idno_idx ON physics_majors_nt(idno);

INSERT INTO students (graduation) VALUES ('01-JUN-03');
UPDATE students
SET math_majors =
people_typ (person_typ(12, 'Bob Jones', '650-555-0130'),
person_typ(31, 'Sarah Chen', '415-555-0120'),
person_typ(45, 'Chris Woods', '415-555-0124')),
chem_majors =
people_typ (person_typ(51, 'Joe Lane', '650-555-0140'),
person_typ(31, 'Sarah Chen', '415-555-0120'),
person_typ(52, 'Kim Patel', '650-555-0135')),
physics_majors =
people_typ (person_typ(12, 'Bob Jones', '650-555-0130'),
person_typ(45, 'Chris Woods', '415-555-0124'))
WHERE graduation = '01-JUN-03';

SELECT m.idno math_id, c.idno chem_id, p.idno physics_id  FROM students s,
TABLE(s.math_majors) m, TABLE(s.chem_majors) c, TABLE(s.physics_majors) p;

ネストしたカーソルまたはTABLEファンクションを使用すると、ネストした表の個々の要素に簡単にアクセスできます。「コレクションの問合せ」を参照してください。

ネストした表の格納時の表領域の指定

ネストした表は、親表と異なる表領域に格納できます。例5-6では、ネストした表はsystem表領域に格納されます。

例5-6 ネストした表を格納するための別の表領域の指定

-- Requires Ex. 5-1, must remove code in Ex. 5-2 if created
CREATE TABLE people_tab (
people_column people_typ )
NESTED TABLE people_column STORE AS people_column_nt (TABLESPACE system);

TABLESPACE句が指定されていない場合、ネストした表の記憶表は、親表が作成された表領域に作成されます。マルチレベルのネストした表の場合、子表を、直系の親表と同じ表領域に作成します。

ALTER TABLE.. MOVE文を発行して、表を別の表領域に移動できます。ネストした表列を持つ表に対してこの文を発行した場合、親表のみ移動され、ネストした表の記憶表に対してはアクションは実行されません。ネストした表の記憶表を別の表領域に移動するには、記憶表に対してALTER TABLE.. MOVEを発行します。次に例を示します。

ALTER TABLE people_tab MOVE TABLESPACE system;  -- moving table
ALTER TABLE people_column_nt MOVE TABLESPACE example; -- moving storage table

people_tab表はsystem表領域に格納され、ネストした表記憶域はexample表領域に格納されました。

VARRAYおよびネストした表要素のサイズおよび精度の増加

VARRAY型の要素型またはネストした表型が可変文字、RAW型または数値型の場合、可変文字またはRAW型のサイズを大きくするか、数値型の精度を向上できます。VARRAY型またはネストした表型の新しい型バージョンが生成されます。

これらの変更は、ALTER TYPE..MODIFY文を使用して行います。この文には次のオプションがあります。

- INVALIDATE: すべての依存オブジェクトを無効とします。

- CASCADE: 変更をその型および表の依存オブジェクトに伝播します。

関連項目:
INVALIDATEおよびCASCADEの詳細な説明は、「型進化に使用するALTER TYPE文」を参照してください。

例5-7では、VARRAYおよびネストした表の要素の型のサイズを大きくします。

例5-7 VARRAYおよびネストした表の要素の型のサイズの増加

CREATE TYPE email_list_arr AS VARRAY(10) OF VARCHAR2(80);
/
ALTER TYPE email_list_arr MODIFY ELEMENT TYPE VARCHAR2(100) CASCADE;

CREATE TYPE email_list_tab AS TABLE OF VARCHAR2(30);
/
ALTER TYPE email_list_tab MODIFY ELEMENT TYPE VARCHAR2(40) CASCADE;

VARRAYの制限サイズの増加

ALTER TYPE ... MODIFY LIMIT構文を使用して、VARRAY型の要素の数を増加できます。数が増加すると、VARRAY型の新しい型バージョンが生成され、型変更履歴の一部となります。

ALTER TYPE ... MODIFY LIMIT文には次のオプションがあります。

- INVALIDATE: すべての依存オブジェクトを無効とします。

- CASCADE: 変更をその型および表の依存オブジェクトに伝播します。

例5-8 VARRAYの制限サイズの増加

-- if you have already creating following types, drop them.
DROP TYPE email_list_tab FORCE;
DROP TYPE email_list_arr FORCE;
CREATE TYPE email_list_arr AS VARRAY(10) OF VARCHAR2(80);
/
CREATE TYPE email_list_typ AS OBJECT (
section_no   NUMBER,
emails       email_list_arr);
/

CREATE TYPE email_varray_typ AS VARRAY(5) OF email_list_typ;
/

ALTER TYPE email_varray_typ MODIFY LIMIT 100 INVALIDATE;

VARRAY型が変更されると、その変更は依存表に伝播されます。「VARRAYのサイズ変更の伝播」を参照してください。

LOB参照が含まれているVARRAYの作成

LOB参照のVARRAYを作成するには、まずREF email_list_typ型のVARRAY型を定義します。注意: email_list_typは例5-8で定義したものです。次に、表dept_email_listを作成し、その中に配列型の列email_addrsを定義します。

例5-9 LOB参照を含むVARRAYの作成

-- Requires Ex. 5-8
CREATE TYPE ref_email_varray_typ AS VARRAY(5) OF REF email_list_typ;
/

CREATE TABLE dept_email_list (
dept_no NUMBER,
email_addrs ref_email_varray_typ)
VARRAY email_addrs STORE AS LOB dept_emails_lob3;

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

マルチレベル・コレクション型とは、要素自体が直接的または間接的に別のコレクション型であるコレクション型です。使用可能なマルチレベル・コレクション型は、次のとおりです。

- ネストした表型のネストした表

- VARRAY型のネストした表

- ネストした表型のVARRAY

- VARRAY型のVARRAY

- ネストした表またはVARRAY型である属性を持つユーザー定義型のネストした表またはVARRAY

シングルレベル・コレクション型と同様に、マルチレベル・コレクション型には次の特徴があります。

- リレーショナル表の列として、またはオブジェクト表のオブジェクト属性とともに使用できます。

- 代入では、ソースとターゲットにいずれも同じデータ型が宣言されている必要があります。

この項の内容は次のとおりです。

- マルチレベル・コレクション型のネストした表の記憶表

- マルチレベル・コレクションのVARRAY記憶域

- マルチレベル・コレクションのコンストラクタ

マルチレベル・コレクション型のネストした表の記憶表

「ネストした表の要素の格納」で説明したように、ネストした表型の列またはオブジェクト表属性には、ネストした表すべての行を格納するための記憶表が必要になります。ネストした表のマルチレベル・コレクションの場合、ネストした表の内側のセットと外側のセットのいずれについても、ネストした表の記憶域の句を指定する必要があります。

関連項目:
「マルチレベル・コレクションを伴う問合せのネスト解除」

例5-10では、ネストした表のネストした表であるマルチレベル・コレクション型nt_country_typを作成します。この例では、それぞれの地域に国のネストした表のコレクションが存在し、それぞれの国にその所在地のネストした表のコレクションが存在する企業の地域体系をモデル化します。この例では、Oracle HRサンプル・スキーマのregions、countriesおよびlocations表が必要です。

関連項目:
サンプル・スキーマの使用方法の詳細は、『Oracle Databaseサンプル・スキーマ』を参照してください。

例5-10のSQL文は、型がマルチレベル・コレクション(nt_country_typ)である列countriesが含まれる表region_tabを作成します。このマルチレベル・コレクションは、ネストした表属性locationsを持つオブジェクト型のネストした表です。外側のネストした表countriesと内側のネストした表locationsに対し、別々のネストした表句が用意されています。

例5-10 マルチレベルのネストした表の記憶域

-- Requires the HR sample schema
CREATE TYPE location_typ AS OBJECT (
location_id      NUMBER(4),
street_address   VARCHAR2(40),
postal_code      VARCHAR2(12),
city             VARCHAR2(30),
state_province   VARCHAR2(25));
/

CREATE TYPE nt_location_typ AS TABLE OF location_typ;  -- nested table type
/

CREATE TYPE country_typ AS OBJECT (
country_id     CHAR(2),
country_name   VARCHAR2(40),
locations      nt_location_typ); -- inner nested table
/

CREATE TYPE nt_country_typ AS TABLE OF country_typ;  -- multilevel collection type
/

CREATE TABLE region_tab (
region_id     NUMBER,
region_name   VARCHAR2(25),
countries     nt_country_typ) -- outer nested table
NESTED TABLE countries STORE AS nt_countries_tab
(NESTED TABLE locations STORE AS nt_locations_tab);

例5-10では、このネストした表はオブジェクトの名前付き属性になっているため、内側のネストした表locationsを名前で参照できます。ただし、内側のネストした表がオブジェクトの属性でない場合には、名前はありません。この場合には、キーワードCOLUMN_VALUEが用意されています。

例5-11では、内側のネストした表に対して名前のかわりにキーワードCOLUMN_VALUEを使用しています。

例5-11 COLUMN_VALUEキーワードを使用したマルチレベルのネストした表の記憶域

CREATE TYPE inner_table AS TABLE OF NUMBER;
/
CREATE TYPE outer_table AS TABLE OF inner_table;
/
CREATE TABLE tab1 (
col1 NUMBER,  -- inner nested table, unnamed
col2 outer_table)
NESTED TABLE col2 STORE AS col2_ntab
(NESTED TABLE COLUMN_VALUE STORE AS cv_ntab);

例5-12に、ネストした表の句の中で記憶表の物理属性を指定する方法を示します。

例5-12 ネストした表の記憶域の物理属性の指定

-- Requires Ex. 5-10
-- drop the following if you have previously created it
DROP TABLE region_tab FORCE;

CREATE TABLE region_tab (
region_id     NUMBER,
region_name   VARCHAR2(25),
countries     nt_country_typ)
NESTED TABLE countries STORE AS nt_countries_tab (
(PRIMARY KEY (NESTED_TABLE_ID, country_id))
ORGANIZATION INDEX COMPRESS
NESTED TABLE locations STORE AS nt_locations_tab);

ネストした表のどの記憶表も、NESTED_TABLE_IDで参照可能な列を含んでいます。この列は、記憶表内の行を、親表内の関連する行と対応付けます。それ自体がネストした表である親表には、システムから提供されたID列が2つあります。

- システムから提供された、NESTED_TABLE_IDにより参照可能なID列。これにより、その行が親表の行に再び関連付けられます。

- システムから提供された、ネストした表の子の中のNESTED_TABLE_ID列により隠蔽および参照されるID列。

例5-12では、ネストした表countriesにORGANIZATION INDEX句を追加し、ネストした表に1列目がNESTED_TABLE_IDになっている主キーを割り当て、この表を索引構成表(IOT)にしています。この列には、記憶表の行が関連付けられた親表内の行のIDが入っています。NESTED_TABLE_IDを使用して主キーを1列目として指定し、表の索引構成を行うと、同じ親である行に属するネストした表の行すべてが、物理的にクラスタ化され、さらに効率的にアクセスできるようになります。

NESTED_TABLE_ID列とともに主キーを指定しない場合、パフォーマンスの向上のためにNESTED_TABLE_ID列のBツリー索引が自動的に作成されます。

ネストした表のそれぞれが、専用の表記憶域句を必要とします。したがって、ネストした表の記憶域句はコレクションに存在するネストした表のレベルと同数用意する必要があります。「ネストした表の記憶域」を参照してください。

マルチレベル・コレクションのVARRAY記憶域

マルチレベルVARRAYの格納方法は、VARRAYが複数個あるVARRAYの1つである場合と、ネストした表の1つのVARRAYである場合とでは異なります。

- 複数個あるVARRAYの中の1つのVARRAYの場合、そのサイズが約4000バイト以上の場合、またはLOB記憶域が明示的に指定されている場合を除き、VARRAY全体がインラインで行に格納されます。

- ネストした表のVARRAYの場合、VARRAY全体がLOBに格納され、LOBロケータのみが行に格納されます。VARRAYのネストした表要素と関連付けられた記憶表は、存在しません。

VARRAYについては、LOB記憶域を明示的に指定できます。次の例では、VARRAY要素のネストした表に対してこの指定を行います。

例5-13に、VARRAY型のVARRAYについて指定された明示的なLOB記憶域を示します。

例5-13 VARRAY型のVARRAYに使用するLOB記憶域の指定

-- Requires Ex. 5-8, drop following if created

DROP TYPE email_varray_typ FORCE;
CREATE TYPE email_list_typ2 AS OBJECT (
section_no   NUMBER,
emails       email_list_arr);
/

CREATE TYPE email_varray_typ AS VARRAY(5) OF email_list_typ2;
/

CREATE TABLE dept_email_list2 (
dept_no NUMBER,
email_addrs email_varray_typ)
VARRAY email_addrs STORE AS LOB dept_emails_lob2;

「VARRAYの記憶域上の考慮点」を参照してください。『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』も参照してください。

例5-14 VARRAYのネストした表に使用するLOB記憶域の指定

-- drop the following types if you have created them
DROP TYPE email_list_typ FORCE;
DROP TABLE dept_email_list FORCE;
DROP TYPE email_list_arr FORCE;

CREATE TYPE email_list_arr AS VARRAY(10) OF VARCHAR2(80);
/

CREATE TYPE email_list_typ AS TABLE OF email_list_arr;
/

CREATE TABLE dept_email_list (
dept_no NUMBER,
email_addrs email_list_typ)
NESTED TABLE email_addrs STORE AS email_addrs_nt
(
VARRAY COLUMN_VALUE STORE AS LOB
dept_emails_lob);

例5-14では、VARRAYとともにCOLUMN_VALUEキーワードを使用しています。このキーワードの説明、およびこれをネストした表に対して使用する方法は、例5-11を参照してください。

マルチレベル・コレクションのコンストラクタ

マルチレベル・コレクション型は、シングルレベル・コレクションやその他のオブジェクト型と同様、個々の型のコンストラクタをコールして作成します。マルチレベル・コレクション型のコンストラクタはシステム定義ファンクションの1つで、型と同じ名前を持ち、その型の新しいインスタンスを戻します。コンストラクタ・パラメータは、オブジェクト型の属性の名前と型を持ちます。

例5-15に、マルチレベル・コレクション型nt_country_typのコンストラクタ・コールを示します。nt_country_typコンストラクタがcountry_typコンストラクタをコールし、country_typコンストラクタがnt_location_typコンストラクタをコールし、nt_location_typコンストラクタがlocation_typコンストラクタをコールします。

注意:
nt_country_typは、別のネストした表が属性として含まれるネストした表であるため、マルチレベル・コレクションです。

例5-15 マルチレベル・コレクションのコンストラクタの使用

-- Requires 5-10 and HR sample schema
INSERT INTO region_tab
VALUES(1, 'Europe', nt_country_typ(
country_typ( 'IT', 'Italy', nt_location_typ (
location_typ(1000, '1297 Via Cola di Rie','00989','Roma', ''),
location_typ(1100, '93091 Calle della Testa','10934','Venice','') )
),
country_typ( 'CH', 'Switzerland', nt_location_typ (
location_typ(2900, '20 Rue des Corps-Saints', '1730', 'Geneva', 'Geneve'),
location_typ(3000, 'Murtenstrasse 921', '3095', 'Bern', 'BE') )
),
country_typ( 'UK', 'United Kingdom', nt_location_typ (
location_typ(2400, '8204 Arthur St', '', 'London', 'London'),
location_typ(2500, 'Magdalen Centre, The Oxford Science Park', 'OX9 9ZB',
'Oxford', 'Oxford'),
location_typ(2600, '9702 Chester Road', '09629850293', 'Stretford',
'Manchester') )
)
)
);

コレクション・データ型の操作

この項では、コレクション・データ型に対する操作について説明します。

この項の内容は次のとおりです。

- コレクションの問合せ

- コレクションを対象としたDML操作の実行

- 結果セット全部を戻すためのBULK COLLECTの使用

- ネストした表を比較する条件

- ネストした表の多重集合操作

コレクションの問合せ

列または属性としてコレクション型が含まれる表を問い合せるには、次の2つの一般的な方法があります。

- コレクションが含まれる結果行の中にコレクションをネストします。

- それぞれのコレクション要素が単独で1行に現れるように、コレクションを分散またはネスト解除します。

コレクション問合せの結果のネスト化

次の各問合せでは、例5-3に示したdepartment_persons表を使用します。列dept_empsは、person_typ型のネストした表コレクションです。dept_empsコレクション列は、通常のスカラー列としてSELECT構文のリストに現れます。この方法でSELECT構文のリスト内のコレクション列を問い合せると、コレクションと関連付けられた結果行の中のコレクションの各要素がネスト化されます。

例5-16の問合せでは、従業員のネストしたコレクションが取り出されます。

例5-16 コレクション問合せの結果のネスト化

-- Requires Ex. 5-1 and Ex. 5-3
SELECT d.dept_emps
FROM department_persons d;

DEPT_EMPS(IDNO, NAME, PHONE)
-------------------------------------------------------------
PEOPLE_TYP(PERSON_TYP(1, 'John Smith', '1-650-555-0135'),
PERSON_TYP(2, 'Diane Smith', '1-650-555-0135'))

SELECT構文のリスト内のオブジェクト型列にコレクション属性が入っている場合は、SELECT構文のリスト自体に、そのコレクションが明示的にリストされていなくても、結果もネストされます。たとえば、SELECT * FROM department_personsという問合せを行うと、ネストされた結果が作成されます。

コレクション問合せの結果のネスト解除

すべてのツールやアプリケーションが、ネストされた形式の結果を処理できるとはかぎりません。従来のフォーマットを必要とするツールを使用してOracleコレクション・データを参照するには、1つの行のコレクション属性をネスト解除またはフラット化して1つ以上のリレーショナル行にする必要があります。そのためには、コレクションとともにTABLE式を使用します。TABLE式を使用すると、表と同様の方法で、FROM句でコレクションを問い合せることができます。つまり、ネストした表が入っている行とネストした表を結合する操作をします。

TABLE式は、変数やパラメータなどの一時値を含むコレクション値式の問合せに使用できます。

関連項目:
TABLE式およびコレクションのネスト解除の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

例5-17の問合せでは、例5-16と同様に従業員のコレクションが取り出されますが、コレクションはネスト解除されます。

例5-17 コレクション問合せの結果のネスト解除

-- Requires Ex. 5-1 and 5-3
SELECT e.*
FROM department_persons d, TABLE(d.dept_emps) e;

IDNO NAME PHONE
---------- ------------------------------ ---------------
1 John Smith 1-650-555-0135
2 Diane Smith 1-650-555-0135

例5-17では、TABLE式がそれ自身の表別名を持つことができることがわかります。TABLE式の表別名は、TABLE式によって戻される列を選択するために、SELECT構文のリストの中にあります。

TABLE式は、別の表別名を使用して、TABLE式が参照するコレクション列が含まれている表を指定します。TABLE(d.dept_emps)式は、dept_empsコレクション列が含まれている表としてdepartment_persons表を指定します。表列を参照するには、TABLE式でFROM句の式の左側にある表の表別名を使用できます。これを左相関といいます。

次の例では、使用するTABLE式の表別名を指定するために、FROM句にdepartment_persons表がリストされています。結果として生成されるdepartment_persons表の列は、TABLE式によって参照される列にかぎられます。

次の例は、従業員のいる部門の行のみを取り出します。

SELECT d.dept_no, e.*
FROM department_persons d, TABLE(d.dept_emps) e;

従業員のいない部門の行も取り出すには、外部結合構文を使用します。

SELECT d.dept_no, e.*
FROM department_persons d, TABLE(d.dept_emps) (+) e;

(+)は、department_personsとe.dept_empsとの間の依存結合を、NULLで拡張することを示しています。つまり、department_personsからは、e.dept_empsがNULLまたは空である行も出力に含められ、それらの行のe.dept_empsに対応する列には、NULL値が設定されます。

TABLE式の副問合せが含まれている問合せのネスト解除

「コレクション問合せの結果のネスト解除」の例は、コレクションの名前が入っているTABLE式を示しています。もう1つの方法は、TABLE式に、コレクションの副問合せを含めるというものです。

例5-18では、部門番号が101である従業員のコレクションが戻されます。

例5-18 コレクションの副問合せが含まれているTABLE式の使用

-- Requires Ex. 5-1 and 5-3
SELECT *
FROM TABLE(SELECT d.dept_emps
FROM department_persons d
WHERE d.dept_no = 101);

TABLE式の中の副問合せには、次の制限があります。

- 副問合せでは、コレクション型を戻す必要があります。

- 副問合せのSELECT構文のリストには、1つの項目を入れる必要があります。

- 副問合せでは、1つのコレクションのみを戻す必要があります。複数行についてのコレクションを戻すことはできません。たとえば、副問合せSELECT dept_emps FROM department_personsは、表department_personsに1つの行のみ入っている場合にかぎり、TABLE式で成功します。表に複数行が含まれている場合、副問合せはエラーになります。

例5-19に、CURSOR式に埋め込まれているSELECTのFROM句に使用されているTABLE式を示します。

例5-19 CURSOR式でのTABLE式の使用

-- Requires Ex. 5-1 and 5-3
SELECT d.dept_no, CURSOR(SELECT * FROM TABLE(d.dept_emps))
FROM department_persons d
WHERE d.dept_no = 101;

マルチレベル・コレクションを伴う問合せのネスト解除

問合せのネスト解除は、VARRAYとネストした表のどちらについても、マルチレベル・コレクションでも使用できます。例5-20は、ネストした表のマルチレベルのネストした表コレクションに対して行う問合せのネスト解除を示しています。この問合せでは、それぞれの地域がcountriesのネストした表を持ち、それぞれの国がlocationsのネストした表を持つregion_tab表から、すべてのregions、countriesおよびlocationsの名前が戻されます。

例5-20 TABLEファンクションによるマルチレベル・コレクションを伴う問合せのネスト解除

-- Requires Ex. 5-10 and 5-15
SELECT r.region_name, c.country_name, l.location_id
FROM region_tab r, TABLE(r.countries) c, TABLE(c.locations) l;

-- the following query is optimized to run against the locations table
SELECT l.location_id, l.city
FROM region_tab r, TABLE(r.countries) c, TABLE(c.locations) l;

出力は次のようになります。

REGION_NAME               COUNTRY_NAME                             LOCATION_ID
------------------------- ---------------------------------------- -----------
Europe                    Italy                                           1000
Europe                    Italy                                           1100
Europe                    Switzerland                                     2900
Europe                    Switzerland                                     3000
Europe                    United Kingdom                                  2400
Europe                    United Kingdom                                  2500
Europe                    United Kingdom                                  2600

7 rows selected.

LOCATION_ID CITY
----------- ------------------------------
1000 Roma
1100 Venice
2900 Geneva
3000 Bern
2400 London
2500 Oxford
2600 Stretford

7 rows selected.

実表region_tabの列は第2のSELECT構文のリストには表示されないため、問合せは、直接locations記憶表に対して実行されるように最適化されます。

マルチレベル・コレクションの問合せでは、外部結合構文も使用できます。「ネストを解除する問合せを使用したリレーショナル形式でのオブジェクト・データの表示」を参照してください。

コレクションを対象としたDML操作の実行

Oracleは、コレクションを対象とした次のDML操作をサポートします。

- コレクション全体に対して新しい値を提供する挿入および更新

- ネストした表およびマルチレベルのネストした表に対する個別的またはピース単位の更新(要素の挿入、削除および更新を含む)

VARRAY列を対象としたピース単位の更新はサポートされません。ただし、VARRAY列を基本単位として挿入または更新することはできます。この項の内容は次のとおりです。

- ネストした表を対象にしたピース単位操作

- マルチレベルのネストした表を対象にしたピース単位操作

- VARRAYおよびネストした表を対象にしたアトミック変更

- 基本データ単位としてのコレクション

ネストした表を対象にしたピース単位操作

ネストした表列に対してピース単位の操作を実行する場合、TABLE式を使用します。

TABLE式では、副問合せを使用してネストした表を抽出できます。これによりINSERT文、UPDATE文またはDELETE文を最上位表でなくネストした表に適用できます。

また、CAST演算子も有用です。これらを使用すると、ネストした表を実際にデータベースに格納することなく、ネストした表に対する設定操作をSQL表記法により実行できます。

関連項目:

- 『Oracle Database SQL言語リファレンス』

- 「CAST」

例5-21のDML文は、ネストした表列を対象としたピース単位操作を示しています。

例5-21 コレクションを対象としたピース単位操作

-- Requires Ex. 5-1 and 5-3
INSERT INTO TABLE(SELECT d.dept_emps
FROM department_persons d
WHERE d.dept_no = 101)
VALUES (5, 'Kevin Taylor', '1-408-555-0199');

UPDATE TABLE(SELECT d.dept_emps
FROM department_persons d
WHERE d.dept_no = 101) e
SET VALUE(e) = person_typ(5, 'Kevin Taylor', '1-408-555-0199')
WHERE e.idno = 5;

DELETE FROM TABLE(SELECT d.dept_emps
FROM department_persons d
WHERE d.dept_no = 101) e
WHERE e.idno = 5;

例5-22は、更新の目的でオブジェクト・インスタンス行を戻すためにVALUEを使用しています。

例5-22 VALUEによるネストした表の更新

-- Requires Ex. 5-1, 5-3
UPDATE TABLE(SELECT d.dept_emps FROM department_persons d
WHERE  d.dept_no = 101) p
SET VALUE(p) = person_typ(2, 'Diane Smith', '1-650-555-0148')
WHERE p.idno = 2;

マルチレベルのネストした表を対象にしたピース単位操作

ピース単位のDMLは、マルチレベルのネストした表に対してのみ実行でき、マルチレベルのVARRAYに対しては実行できません。「基本データ単位としてのコレクション」で説明するように、DML操作は、VARRAYとネストした表のいずれのマルチレベル・コレクションに対しても基本単位として実行できます。

例5-23は、ネストした表のネストした表countriesに対して行うピース単位挿入操作を示しています。この例は、新しい国にlocation_typのネストした表を付けて挿入します。

例5-23 マルチレベル・コレクションに対するピース単位INSERT

-- Requires Ex. 5-10 and 5-15
INSERT INTO TABLE( SELECT countries FROM region_tab r WHERE r.region_id = 2)
VALUES ( 'CA', 'Canada', nt_location_typ(
location_typ(1800, '147 Spadina Ave', 'M5V 2L7', 'Toronto', 'Ontario')));

例5-24では、ピース単位挿入操作を実行して、内側のネストした表を挿入し、国の所在地を追加します。この例も、前述の例と同様、内側のネストした表を選択して、挿入のターゲットを指定する副問合せが含まれているTABLE式を使用します。

例5-24 内側のネストした表に対するピース単位INSERT

-- Requires Ex. 5-10 and 5-15
INSERT INTO TABLE( SELECT c.locations
FROM TABLE( SELECT r.countries FROM region_tab r WHERE r.region_id = 2) c
WHERE c.country_id = 'US')
VALUES (1700, '2004 Lakeview Rd', '98199', 'Seattle', 'Washington');

SELECT r.region_name, c.country_name, l.location_id
FROM region_tab r, TABLE(r.countries) c, TABLE(c.locations) l;

VARRAYおよびネストした表を対象にしたアトミック変更

この項では、ネストした表およびVARRAYに対するアトミック変更について説明します。

注意: ネストした表はピース単位での変更も可能ですが、VARRAYはピース単位で変更することはできません。

例5-25は、SQLのVARRAYオブジェクト型をPL/SQL文で操作する方法を示しています。この例では、VARRAYをPL/SQL変数とSQL表の間で転送しています。この例のようにして、コレクションを含む行を挿入したり、行を更新してコレクションを置き換えたり、コレクションをPL/SQL変数内で選択したりできます。

ただし、VARRAYの個々の要素をSQLで直接更新したり削除することはできません。表からVARRAYを選択し、PL/SQLで変更した後、新しいVARRAYを含むように表を更新する必要があります。この操作はネストした表でも行うことができますが、ネストした表には、ピース単位の更新および削除を行うこともできます。

例5-25 VARRAYに対するINSERT文、UPDATE文、DELETE文およびSELECT文の使用

CREATE TYPE dnames_var IS VARRAY(7) OF VARCHAR2(30);
/
CREATE TABLE depts (region VARCHAR2(25), dept_names dnames_var);
BEGIN
INSERT INTO depts VALUES('Europe', dnames_var('Shipping','Sales','Finance'));
INSERT INTO depts VALUES('Americas', dnames_var('Sales','Finance','Shipping'));
INSERT INTO depts
VALUES('Asia', dnames_var('Finance','Payroll','Shipping','Sales'));
COMMIT;
END;
/
DECLARE
new_dnames dnames_var := dnames_var('Benefits', 'Advertising', 'Contracting',
'Executive', 'Marketing');
some_dnames dnames_var;
BEGIN
UPDATE depts SET dept_names  = new_dnames WHERE region = 'Europe';
COMMIT;
SELECT dept_names INTO some_dnames FROM depts WHERE region = 'Europe';
FOR i IN some_dnames.FIRST .. some_dnames.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('dept_names = ' || some_dnames(i));
END LOOP;
END;
/

基本データ単位としてのコレクション

「マルチレベル・コレクションのコンストラクタ」の項で、INSERT文を使用してマルチレベル・コレクション全体を挿入する例を示しました。マルチレベル・コレクション(VARRAYまたはネストした表にかかわらず)は、UPDATE文を使用しても基本単位として更新できます。たとえば、v_countryがcountries のネストした表型nt_country_typとして宣言された変数であるとします。

例5-26では、countriesコレクションを1つの単位としてv_countryの値に設定することで、region_tabを更新します。

例5-26 UPDATEを使用したマルチレベル・コレクション全体の挿入

-- Requires Ex. 5-10 and 5-15
INSERT INTO region_tab (region_id, region_name) VALUES(2, 'Americas');

DECLARE
v_country nt_country_typ;
BEGIN
v_country :=  nt_country_typ( country_typ(
'US', 'United States of America', nt_location_typ (
location_typ( 1500,'2011 Interiors Blvd','99236','San Francisco','California'),
location_typ(1600,'2007 Zagora St','50090','South Brunswick','New Jersey'))));
UPDATE region_tab r
SET r.countries = v_country WHERE r.region_id = 2;
END;
/
-- Invocation:
SELECT r.region_name, c.country_name, l.location_id
FROM region_tab r, TABLE(r.countries) c, TABLE(c.locations) l
WHERE r.region_id = 2;

結果セット全部を戻すためのBULK COLLECTの使用

PL/SQL句BULK COLLECTは、処理に時間のかかるDML文を使用しない方法の1つです。結果セット全部を1つの操作で戻すことができます。

例5-27では、オブジェクト型を含むマルチレベル・コレクションに対してBULK COLLECTを使用しています。

例5-27 コレクションに対するBULK COLLECTの使用

-- unrelated to other examples in this chapter
CREATE TYPE dnames_var IS VARRAY(7) OF VARCHAR2(30);
/
CREATE TABLE depts (region VARCHAR2(25), dept_names dnames_var);
BEGIN
INSERT INTO depts VALUES('Europe', dnames_var('Shipping','Sales','Finance'));
INSERT INTO depts VALUES('Americas', dnames_var('Sales','Finance','Shipping'));
INSERT INTO depts
VALUES('Asia', dnames_var('Finance','Payroll','Shipping','Sales'));
COMMIT;
END;
/
DECLARE
TYPE dnames_tab IS TABLE OF dnames_var;
v_depts dnames_tab;
BEGIN
SELECT dept_names BULK COLLECT INTO v_depts FROM depts;
DBMS_OUTPUT.PUT_LINE(v_depts.COUNT); -- prints 3
END;
/

ネストした表を比較する条件

この項で示す条件を使用すると、ネストした表(マルチレベルのネストした表を含む)を比較できます。VARRAYを比較するためのメカニズムはありません。この項のSQLの例では、例5-5で作成したネストした表を使用し、例5-1で作成したオブジェクトが含まれています。

等価および非等価比較

等価(=)および非等価(<>)条件は、入力されたネストした表が同一であるかどうかを判断し、結果をブール値として戻します。

同一の名付けられた型およびカーディナリティを持ち、要素が等価である場合、2つのネストした表は等価です。要素が等価であるかどうかは、マップ・メソッドを必要とするオブジェクト型を除き、要素自体の等価性定義によって等価であるかどうかに依存します。ネストした表には順序がないため、等価性は要素の既存の順序で決定されます。

例5-28 ネストした表への等価比較の使用

-- Requires Ex. 5-1 and 5-5
SELECT p.name
FROM students, TABLE(physics_majors) p
WHERE math_majors = physics_majors;

例5-28では、ネストした表には、関連付けられたマップ・メソッドを持つperson_typオブジェクトが含まれています。例5-1を参照してください。WHERE句の2つのネストした表は等しくないため、行は選択されません。

IN比較

IN条件は、特定のネストした表が、ネストした表のリストに含まれているかどうかを確認し、結果をブール値として戻します。ネストした表がNULLのネストした表の場合、NULLが戻されます。

例5-29 ネストした表へのIN比較の使用

-- Requires Ex. 5-1 and 5-5
SELECT p.idno, p.name
FROM students, TABLE(physics_majors) p
WHERE physics_majors IN (math_majors, chem_majors);

多重集合比較のサブセット

SUBMULTISET [OF]条件は、特定のネストした表が、別のネストした表のサブセットであるかどうかを確認し、結果をブール値として戻します。OFキーワードはオプションで、SUBMULTISETの機能を変更しません。

この条件は、ネストした表のみに実装されます。

関連項目:
「ネストした表の多重集合操作」

例5-30 ネストした表に対するSUBMULTISET OF条件のテスト

-- Requires Ex. 5-1 and 5-5
SELECT p.idno, p.name
FROM students, TABLE(physics_majors) p
WHERE physics_majors SUBMULTISET OF math_majors;

ネストした表のメンバー比較

MEMBER [OF]またはNOT MEMBER [OF]条件は、特定の要素がネストした表のメンバーであるかどうかを確認し、結果をブール値として戻します。OFキーワードはオプションで、出力に影響を与えません。

例5-31で、person_typは、ネストした表math_majorsの要素と同じ型の要素です。

例5-31 ネストした表へのMEMBER OFの使用

-- Requires Ex. 5-1 and 5-5
SELECT graduation
FROM students
WHERE person_typ(12, 'Bob Jones', '1-650-555-0130') MEMBER OF math_majors;

例5-32では、MEMBER OF条件を使用しないアプローチを示します。サイズの大きいコレクションの場合、この方法のほうが実行効率が高くなります。

例5-32 ネストした表へのMEMBER OFを使用しない方法

-- Requires Ex. 5-1 and 5-5
SELECT graduation
FROM students
WHERE person_typ(12, 'Bob Jones', '1-650-555-0130') in (select value(p)
from TABLE( math_majors) p);

Empty比較

IS [NOT] EMPTY条件は、指定されたネストした表が空であるかどうかを確認します(いずれかの要素がNULLであるかどうかは問われません)。ネストした表がNULLの場合、結果はNULLです。結果はブール値として戻されます。

例5-33 ネストした表へのIS NOTの使用

-- Requires Ex. 5-1 and 5-5
SELECT p.idno, p.name
FROM students, TABLE(physics_majors) p
WHERE physics_majors IS NOT EMPTY;

Set比較

IS [NOT] A SET条件は、指定されたネストした表が一意の要素で構成されているかどうかを確認し、結果をブール値として戻します。

例5-34 ネストした表へのIS A SETの使用

-- Requires Ex. 5-1 and 5-5
SELECT p.idno, p.name
FROM students, TABLE(physics_majors) p
WHERE physics_majors IS A SET;

ネストした表の多重集合操作

この項では、ネストした表に対する多重集合操作について説明します。VARRAYには多重集合操作を実行できません。

この項のSQLの例では、例5-5で作成したネストした表と、例5-1で作成したオブジェクトを使用します。

関連項目:

- その他の操作の詳細は、「オブジェクトに便利なファンクションおよび演算子」を参照してください。

- ネストした表で演算子を使用する場合の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CARDINALITY

CARDINALITYファンクションは、ネストした表に含まれている要素の数を戻します。戻り型はNUMBERです。ネストした表がNULLコレクションの場合、NULLが戻されます。

例5-35 ネストした表のCARDINALITYの判別

-- Requires Ex. 5-1 and 5-5
SELECT CARDINALITY(math_majors)
FROM students;

CARDINALITYファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

COLLECT

COLLECTファンクションは集計関数で、要素のセットから多重集合を作成します。入力として要素型の列を取り、選択された行から多重集合を作成します。このファンクションの結果を取得するには、COLLECTの出力型を指定するために、CASTファンクション内で使用する必要があります。COLLECTファンクションの例は、「CAST」を参照してください。

COLLECTファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

MULTISET EXCEPT

MULTISET EXCEPT演算子は、2つのネストした表を入力として取り、最初のネストした表にのみ含まれ、2番目のネストした表には含まれていない要素のネストした表を戻します。入力のネストした表と出力のネストした表は、すべて同じネストした表の型です。

この演算子とともに、ALLまたはDISTINCTオプションを使用できます。デフォルトは、ALLです。

- ALLオプションを使用すると、ntab1 MULTISET EXCEPT ALL ntab2の場合、ntab2に含まれている要素を除くntab1のすべての要素が、結果に含まれます。特定の要素が、ntab1ではm回、ntab2ではn回出現する場合、mがnより大きければ、結果にはこの要素が(m - n)回出現し、それ以外は、この要素は0回出現します。

- DISTINCTオプションを使用すると、ntab1に存在し、ntab2にも存在する要素は、出現回数に関係なく削除されます。

例5-36 ネストした表に対するMULTISET EXCEPT操作の使用

-- Requires Ex. 5-1 and 5-5
SELECT math_majors MULTISET EXCEPT physics_majors
FROM students
WHERE graduation = '01-JUN-03';

MULTISET EXCEPT演算子の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

MULTISET INTERSECT

MULTISET INTERSECT演算子は、入力された2つのネストした表に共通する値で構成されるネストした表を戻します。入力のネストした表と出力のネストした表は、すべて、型の名前が等価です。

この演算子には、ALLまたはDISTINCTオプションが関連付けられています。デフォルトは、ALLです。ALLオプションを使用すると、特定の値が、ntab1ではm回、ntab2ではn回出現する場合、結果にはこの要素がMIN(m, n)回出現します。DISTINCTオプションの場合、結果から重複する要素は削除されます(NULL値が重複する場合はこれも含まれます)。

例5-37 ネストした表に対するMULTISET INTERSECT操作の使用

-- Requires Ex. 5-1 and 5-5
SELECT math_majors MULTISET INTERSECT physics_majors
FROM students
WHERE graduation = '01-JUN-03';

MULTISET INTERSECT演算子の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

MULTISET UNION

MULTISET UNION演算子は、入力された2つのネストした表の値で構成されるネストした表を戻します。入力のネストした表と出力のネストした表は、すべて、型の名前が等価です。

この演算子には、ALLまたはDISTINCTオプションが関連付けられています。デフォルトは、ALLです。ALLオプションを使用すると、ntab1およびntab2に含まれるすべての要素が、NULLのすべてのコピーを含め、結果に含まれます。特定の要素がntab1ではm回、ntab2ではn回出現する場合、結果にはこの要素が(m + n)回出現します。DISTINCTオプションの場合、結果から重複する要素は削除されます(NULL値が重複する場合はこれも含まれます)。

例5-38 ネストした表に対するMULTISET UNION操作の使用

-- Requires Ex. 5-1 and 5-5
SELECT math_majors MULTISET UNION DISTINCT physics_majors
FROM students
WHERE graduation = '01-JUN-03';

PEOPLE_TYP(PERSON_TYP(12, 'Bob Jones', '1-650-555-0130'),
PERSON_TYP(31, 'Sarah Chen', '1-415-555-0120'),
PERSON_TYP(45, 'Chris Woods', '1-408-555-0128'))

-- Requires Ex. 5-1 and 5-5
SELECT math_majors MULTISET UNION ALL physics_majors
FROM students
WHERE graduation = '01-JUN-03';

PEOPLE_TYP(PERSON_TYP(12, 'Bob Jones', '1-650-555-0130'),
PERSON_TYP(31, 'Sarah Chen', '1-415-555-0120'),
PERSON_TYP(45, 'Chris Woods', '1-408-555-0128'),
PERSON_TYP(12, 'Bob Jones', '1-650-555-0130'),
PERSON_TYP(45, 'Chris Woods', '1-408-555-0128'))

MULTISET UNION演算子の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

POWERMULTISET

POWERMULTISETファンクションは、指定された多重集合から、すべての空でないサブ多重集合を生成します。POWERMULTISETファンクションの入力には、多重集合と評価されるすべての式を使用できます。多重集合引数のカーディナリティの制限は32です。

例5-39 多重集合に対するPOWERMULTISET操作の使用

-- Requires Ex. 5-1 and 5-5
SELECT * FROM TABLE(POWERMULTISET( people_typ (
person_typ(12, 'Bob Jones', '1-650-555-0130'),
person_typ(31, 'Sarah Chen', '1-415-555-0120'),
person_typ(45, 'Chris Woods', '1-415-555-0124'))));

POWERMULTISETファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

POWERMULTISET_BY_CARDINALITY

POWERMULTISET_BY_CARDINALITYファンクションは、指定されたカーディナリティのネストした表の空でないサブ多重集合をすべて戻します。出力は、ネストした表の行です。

POWERMULTISET_BY_CARDINALITY(x, l)はTABLE(POWERMULTISET(x)) pと等価です。CARDINALITY(value(p)) = l、xは多重集合で、1は指定されたカーディナリティです。

POWERMULTISET_BY_CARDINALITYの最初の入力パラメータには、ネストした表と評価されるすべての式を使用できます。長さのパラメータには正の整数を使用する必要があり、それ以外はエラーが戻されます。ネストした表引数のカーディナリティの制限は32です。

例5-40 POWERMULTISET_BY_CARDINALITYファンクションの使用

-- Requires Ex. 5-1 and 5-5
SELECT * FROM TABLE(POWERMULTISET_BY_CARDINALITY( people_typ (
person_typ(12, 'Bob Jones', '1-650-555-0130'),
person_typ(31, 'Sarah Chen', '1-415-555-0120'),
person_typ(45, 'Chris Woods', '1-415-555-0124')),2));

POWERMULTISET_BY_CARDINALITYファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

SET

SETファンクションは、重複要素を削除することによってネストした表をセットに変換し、要素が互いに固有であるネストした表を戻します。戻されるネストした表は、入力されたネストした表と同一の名付けられた型です。

例5-41 ネストした表に対するSETファンクションの使用

-- Requires Ex. 5-1 and 5-5
SELECT SET(physics_majors)
FROM students
WHERE graduation = '01-JUN-03';

SETファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

Oracleオブジェクトを持つ表のパーティション化

パーティション化は、大規模な表や索引を、パーティションと呼ばれる小さく管理が容易な単位に分解することで、大規模な表や索引のサポート上の主要な問題が解決できます。Oracleでは、オブジェクト、REF、VARRAYおよびネストした表を含む表をパーティション化できるように、パーティション化の機能を拡張しています。LOBに格納されるVARRAYは、LOBのように同一レベル・パーティション化されます。『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』も参照してください。

Oracle Database 11gリリース1 (11.1)では、ネストした表は同一レベル・パーティション化されます。これは、ネストした表に関連付けられた記憶域表のパーティション化は、最上位レベルの実表に対応することを意味します。キーワードLOCALがデフォルト値で、この動作を示します。以前のリリースでは、パーティション化されていないネストした表がパーティション化された実表とともに格納されていました。この動作を取得するには、GLOBALキーワードを指定します。既存のパーティション化されていないネストした表をパーティション化する場合、『Oracle Database VLDBおよびパーティショニング・ガイド』のオンライン再定義に関する項を参照してください。

通常、メンテナンス操作は最上位(親表)に対して実行され、関連付けられているネストした表にカスケードされます。ただし、ネストした表のパーティションに次の操作を直接実行する必要があります。

- デフォルト属性を変更します。つまり、パーティションのデフォルトの物理属性を変更します。

- パーティションを変更します。つまり、表パーティションの物理属性を変更します。

- パーティションを移動します。つまり、表パーティションの内容を別のセグメントまたは別の表領域に移動します。

- パーティションの名前を変更します。つまり、表パーティションに新しい名前を割り当てます。

関連項目:
同一レベル・パーティション化の詳細は、次のマニュアルを参照してください。

- 『Oracle Database VLDBおよびパーティショニング・ガイド』

- 『Oracle XML DB開発者ガイド』

例5-42では、列オブジェクトShipToAddrの属性であるzipコード(ToZip)に従って、発注書の表をパーティション化します。LineItemList_ntのネストした表は、パーティション化されたネストした表の記憶域を示します。

例5-42 オブジェクトを持つネストした表のパーティション化

CREATE TYPE StockItem_objtyp AS OBJECT (
StockNo NUMBER,
Price NUMBER,
TaxRate NUMBER);
/

CREATE TYPE LineItem_objtyp AS OBJECT (
LineItemNo NUMBER,
Stock_ref REF StockItem_objtyp,
Quantity NUMBER,
Discount NUMBER);
/

CREATE TYPE Address_objtyp AS OBJECT (
Street VARCHAR2(200),
City VARCHAR2(200),
State CHAR(2),
Zip VARCHAR2(20))
/

CREATE TYPE LineItemList_nt as table of LineItem_objtyp;
/

CREATE TYPE PurchaseOrder_ntyp AS OBJECT (
PONo                NUMBER,
OrderDate           DATE,
ShipDate            DATE,
OrderForm           BLOB,
LineItemList        LineItemList_nt,
ShipToAddr          Address_objtyp,

MAP MEMBER FUNCTION
ret_value RETURN NUMBER,
MEMBER FUNCTION
total_value RETURN NUMBER);
/

CREATE TABLE PurchaseOrders_ntab of PurchaseOrder_ntyp
LOB (OrderForm) store as (nocache logging)
NESTED TABLE LineItemList STORE AS LineItemList_ntab
PARTITION BY RANGE (ShipToAddr.zip)
(PARTITION PurOrderZone1_part VALUES LESS THAN ('59999')
LOB (OrderForm) store as (
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100))
NESTED TABLE LineItemList store as LineitemZone1_part(
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100)),
PARTITION PurOrderZone2_part  VALUES LESS THAN ('79999')
LOB (OrderForm) store as (
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100))
NESTED TABLE LineItemList store as LineitemZone2_part(
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100)),
PARTITION PurOrderZone3_part  VALUES LESS THAN ('99999')
LOB (OrderForm) store as (
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100))
NESTED TABLE LineItemList store as LineitemZone3_part(
storage (INITIAL 10 MINEXTENTS 10 MAXEXTENTS 100)) )
/

6 オブジェクト・モデルのリレーショナル・データへの適用

この章では、基礎となるリレーショナル・データの構造を変更することなく、オブジェクト指向アプリケーションを作成する方法を示します。

内容は次のとおりです。

- オブジェクト・ビュー使用の利点

- オブジェクト・ビューの定義

- アプリケーションにおけるオブジェクト・ビューの使用

- オブジェクト・ビューにおけるオブジェクトのネスト

- オブジェクト・ビューにおけるNULLオブジェクトの識別

- オブジェクト・ビューにおけるネストした表およびVARRAYの使用

- オブジェクト・ビューに対するオブジェクト識別子の指定

- オブジェクトを表示するための参照の作成

- オブジェクト・ビューを利用した逆リレーションシップのモデル化

- オブジェクト・ビューの更新

- オブジェクト・モデルのリモート表への適用

- オブジェクト・ビューにおける複雑なリレーションシップの定義

- オブジェクト・ビューの階層

オブジェクト・ビュー使用の利点

ビューが仮想表であることと同様、オブジェクト・ビューは仮想的なオブジェクト表です。ビューの各行はオブジェクトであるため、メソッドのコール、ドット表記法を使用したオブジェクト属性へのアクセスおよびオブジェクトを指すREFの作成が可能です。

オブジェクト指向アプリケーションは、既存の表を別の物理構造に変換せずに実行できます。このためには、オブジェクト・ビューを使用して、オブジェクト指向アプリケーションのプロトタイプを作成したり、オブジェクト指向アプリケーションに切り替えることができます。ビューの中のデータはリレーショナル表から取り出すことができ、オブジェクト表として定義されているかのようにアクセスできるためです。

オブジェクト・ビューは、リレーショナル・ビューのように使用し、目的のデータのみ画面上に表示できます。たとえば、給料など機密データを除いて、従業員表の特定のデータを表示するオブジェクト・ビューが作成できます。

オブジェクト・ビューの使用によって、パフォーマンスが向上します。オブジェクト・ビューの1行を構成するリレーショナル・データは、1単位としてネットワークを横断するため、ラウンドトリップが大幅に削減されます。

リレーショナル・データは、クライアント側のオブジェクト・キャッシュにフェッチでき、Cの構造体、C++またはJavaクラスにマップすることもできるので、3GLアプリケーションで固有のクラスのように操作できます。また、複雑なオブジェクト検索のようなオブジェクト指向機能をリレーショナル・データとともに使用することもできます。

- リレーショナル・データからオブジェクトを合成することによって、新しい方法でデータを問い合せることができます。複数の表との複雑な結合を記述するかわりに、オブジェクトの参照解除を利用することで複数の表からデータを表示できます。

- オブジェクト・ビューからオブジェクト・データを確保し、クライアント側のオブジェクト・キャッシュ内でそのデータを使用できます。オブジェクト・キャッシュ上に確保された、これらの合成されたオブジェクトを、専用のオブジェクト検索メカニズムにより取り出すことで、ネットワーク通信量を削減できます。

- ビュー内部にオブジェクト・モデルを作成しながら、モデル開発が継続できるという、優れた柔軟性が得られます。オブジェクト型を変更する必要がある場合、無効なビューを新しい定義に簡単に置換できます。

- ビューの中のオブジェクトを使用することで、基礎となる記憶域メカニズムの特性が制限されることはありません。同様に、現行のテクノロジによって制限されることもありません。たとえば、パラレル化およびパーティション化されたリレーショナル表からオブジェクトを合成することもできます。

- 基礎となる同じデータから異なる複合データ・モデルを作成できます。

関連項目:

- SQL構文および使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- PL/SQLの機能の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- Javaの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

- これらの機能の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

オブジェクト・ビューの定義

オブジェクト・ビューを定義する手順は、次のとおりです。

1. 既存のリレーショナル表の列にそれぞれ対応するデータ型の属性を持つオブジェクト型を定義します。

2. リレーショナル表からデータを抽出する方法を指定する問合せを作成します。オブジェクト型の属性と同じ順序で、リレーショナル表の列を指定します。

3. 基礎となるデータの属性に基づいて、一意の値を指定します。これは、ビュー内のオブジェクトを指すポインタ(REF)を作成するためのオブジェクト識別子となります。既存の主キーを使用することもできます。

関連項目:
「オブジェクト識別子による行オブジェクトの識別」

オブジェクト型の属性が既存の表の列に正確に対応していないオブジェクト・ビューを更新するには、次の手順を実行する必要があることがあります。

アプリケーション・プログラムがオブジェクト・ビューのデータを更新するときに、Oracleに実行させるINSTEAD OFトリガー・プロシージャを作成します。「オブジェクト・ビューの更新」を参照してください。

これで、オブジェクト・ビューをオブジェクト表と同様に使用できます。

例6-1のSQL文は、各行がemployee_t型のオブジェクトであるオブジェクト・ビューを定義しています。

例6-1 オブジェクト・ビューの作成

CREATE TABLE emp_table (
empnum   NUMBER (5),
ename    VARCHAR2 (20),
salary   NUMBER (9,2),
job      VARCHAR2 (20));

CREATE TYPE employee_t AS OBJECT (
empno    NUMBER (5),
ename    VARCHAR2 (20),
salary   NUMBER (9,2),
job      VARCHAR2 (20));
/

CREATE VIEW emp_view1 OF employee_t
WITH OBJECT IDENTIFIER (empno) AS
SELECT e.empnum, e.ename, e.salary, e.job
FROM emp_table e
WHERE job = 'Developer';

insert into emp_table values(1,'John',1000.00,'Architect');
insert into emp_table values(2,'Robert',900.00,'Developer');
insert into emp_table values(3,'James',2000.00,'Director');

select * from emp_view1;

EMPNO ENAME                    SALARY JOB
---------- -------------------- ---------- --------------------
2 Robert                      900 Developer

リレーショナル表のempnum列のデータにアクセスするには、オブジェクト型のempno属性にアクセスします。

アプリケーションにおけるオブジェクト・ビューの使用

オブジェクト・ビューの行にあるデータが複数の表から取り出される可能性もありますが、その場合もオブジェクト・ビューは1つの操作のみでネットワークを横断します。クライアント側のオブジェクト・キャッシュの中では、インスタンスはCまたはC++の構造体として、またはPL/SQLオブジェクト変数として現れます。このインスタンスを、他のすべてのシステム固有の構造体と同様に操作することもできます。

SQL文の中で、オブジェクト・ビューはオブジェクト表と同じ方法で参照できます。たとえば、オブジェクト・ビューが現れる可能性があるのは、SELECT構文のリスト、UPDATE-SET句またはWHERE句の中です。

また、オブジェクト・ビューにオブジェクト・ビューを定義することもできます。

オブジェクト表からオブジェクトに対して使用するものと同じOCIコールを使用して、クライアント側のオブジェクト・ビューのデータにアクセスできます。たとえば、REFを確保するためにOCIObjectPin()を、また、オブジェクトをサーバーにフラッシュするためにOCIObjectFlush()を使用できます。オブジェクト・ビューのオブジェクトをデータベースに更新またはフラッシュすると、データベースでオブジェクト・ビューが更新されます。

関連項目:
OCIコールの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

オブジェクト・ビューにおけるオブジェクトのネスト

オブジェクト型は、他のオブジェクト型を属性として自身にネストさせることができます。

オブジェクト・ビューの基になっているオブジェクト型が、それ自身がオブジェクト型である属性を持っている場合は、オブジェクト・ビューを作成する処理の一部として、この属性用の列オブジェクトを用意する必要があります。属性型の列オブジェクトがリレーショナル表にすでに存在する場合は、この列オブジェクトを選択するのみですみます。存在しない場合は、ビューの主オブジェクト・インスタンスを合成する場合と同様に、基礎となるリレーショナル・データからオブジェクト・インスタンスを合成する必要があります。これらのオブジェクトを合成または作成するには、オブジェクト型の各コンストラクタ・メソッドをコールしてオブジェクト・インスタンスを作成しますが、それらの属性には、コンストラクタで指定したリレーショナル列からデータを移入できます。

たとえば、例6-2の部門表deptについて考えてみます。住所が部門オブジェクト内部のオブジェクトになっているオブジェクト・ビューを作成します。これにより、住所オブジェクト用の再利用可能なメソッドを定義し、様々なアドレスに使用できるようになります。

まず住所オブジェクト用と部門オブジェクト用の型を作成してから、部門番号、名前および住所を含むビューを作成します。リレーショナル表の列から、addressオブジェクトが作成されます。

例6-2 ネストしたオブジェクト型を持つビューの作成

CREATE TABLE dept (
deptno       NUMBER PRIMARY KEY,
deptname     VARCHAR2(20),
deptstreet   VARCHAR2(20),
deptcity     VARCHAR2(10),
deptstate    CHAR(2),
deptzip      VARCHAR2(10));

CREATE TYPE address_t AS OBJECT (
street   VARCHAR2(20),
city    VARCHAR2(10),
state   CHAR(2),
zip     VARCHAR2(10));
/
CREATE TYPE dept_t AS OBJECT (
deptno     NUMBER,
deptname   VARCHAR2(20),
address    address_t );
/

CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER (deptno) AS
SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS
deptaddr
FROM dept d;

insert into dept values(1,'Sales','500 Oracle pkwy','Redwood S','CA','94065');
insert into dept values(2,'ST','400 Oracle Pkwy','Redwood S','CA','94065');
insert into dept values(3,'Apps','300 Oracle pkwy','Redwood S','CA','94065');

select * from dept_view;

DEPTNO DEPTNAME
---------- --------------------
ADDRESS(STREET, CITY, STATE, ZIP)
----------------------------------------------------------------------------------
1 Sales
ADDRESS_T('500 Oracle pkwy', 'Redwood S', 'CA', '94065')

2 ST
ADDRESS_T('400 Oracle Pkwy', 'Redwood S', 'CA', '94065')

3 Apps
ADDRESS_T('300 Oracle pkwy', 'Redwood S', 'CA', '94065')

オブジェクト・ビューにおけるNULLオブジェクトの識別

オブジェクトのコンストラクタからNULLが戻されることはありません。したがって、前述のビューにおいて、リレーショナル表の中のcity、streetなどの列がすべてNULLであっても、アドレス・オブジェクトがNULLになることはありません。リレーショナル表には、部門の住所がNULLかどうかを指定する列はありません。

DECODEファンクションまたは他のファンクションを使用して、NULLまたは構成されたオブジェクトのいずれかを返すことにより、NULLのdeptstreet列によって住所全体がNULLであることを表すことができます。

例6-3 オブジェクト・ビューにおけるNULLオブジェクトの識別

-- Requires Ex. 6-2
CREATE OR REPLACE VIEW dept_view AS
SELECT d.deptno, d.deptname,
DECODE(d.deptstreet, NULL, NULL,
address_t(d.deptstreet, d.deptcity, d.deptstate, d.deptzip)) AS deptaddr
FROM dept d;

部門の住所はリレーショナル表の中の列と直接対応していないため、この方法を使用すると、ビューを介して部門の住所を直接更新できなくなります。この方法ではなく、ビュー上にINSTEAD OFトリガーを定義して、この列の更新を操作します。

オブジェクト・ビューにおけるネストした表およびVARRAYの使用

ネストした表およびVARRAYのコレクションはどちらも、ビューの列になる場合があります。これらのコレクションは、基礎となるコレクション列から選択するか、または副問合せを使用して合成できます。CAST-MULTISET演算子によって、これらのコレクションを合成します。

この項の内容は次のとおりです。

- オブジェクト・ビューのシングルレベル・コレクション

- オブジェクト・ビューのマルチレベル・コレクション

オブジェクト・ビューのシングルレベル・コレクション

最初に例6-1および例6-2を使用することで、empリレーショナル表に存在する各従業員は例6-4の構造を持ちます。このリレーショナル表を使用すると、部門番号、名前、住所および部門に所属する従業員のコレクションを持つdept_viewを構成できます。

まず、従業員型employee_t用のネストした表型を定義します。次に、部門番号、名前、住所、および従業員のネストした表を持つ部門型を定義します。最後に、オブジェクト・ビューdept_viewを定義します。

例6-4 シングルレベル・コレクションを持つビューの作成

-- Requires Ex. 6-1 and Ex. 6-2
CREATE TABLE emp (
empno    NUMBER PRIMARY KEY,
empname  VARCHAR2(20),
salary   NUMBER,
job      VARCHAR2 (20),
deptno   NUMBER REFERENCES dept(deptno));

CREATE TYPE employee_list_t AS TABLE OF employee_t;  -- nested table
/
CREATE TYPE dept_t AS OBJECT (
deptno     NUMBER,
deptname   VARCHAR2(20),
address    address_t,
emp_list   employee_list_t);
/
CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER (deptno) AS
SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr,
CAST( MULTISET (
SELECT e.empno, e.empname, e.salary, e.job
FROM emp e
WHERE e.deptno = d.deptno)
AS employee_list_t)
AS emp_list
FROM dept d;

insert into dept values(100,'ST','400 Oracle Pkwy','Redwood S','CA',94065);
insert into dept values(200,'Sales','500 Oracle Pkwy','Redwood S','CA',94065);
insert into emp values(1,'John',900,'Developer1',100);

insert into emp values(2,'Robert',1000,'Developer2',100);
insert into emp values(3,'Mary', 1000,'Apps1',200);
insert into emp values(4,'Maria',1500,'Developer3',200);
select * from dept_view where deptno = 100;

DEPTNO DEPTNAME
---------- --------------------
ADDRESS(STREET, CITY, STATE, ZIP)
--------------------------------------------------------------------------------
EMP_LIST(EMPNO, ENAME, SALARY, JOB)
--------------------------------------------------------------------------------
100 ST
ADDRESS_T('400 Oracle Pkwy', 'Redwood S', 'CA', '94065')
EMPLOYEE_LIST_T(EMPLOYEE_T(1, 'John', 900, 'Developer1'), EMPLOYEE_T(2, 'Robert'
, 1000, 'Developer2'))

select emp_list from dept_view where deptno = 100;

EMP_LIST(EMPNO, ENAME, SALARY, JOB)
--------------------------------------------------------------------------------
EMPLOYEE_LIST_T(EMPLOYEE_T(1, 'John', 900, 'Developer1'), EMPLOYEE_T(2, 'Robert'
, 1000, 'Developer2'))

CAST-MULTISETブロック内のSELECT副問合せにより、現在の部門に所属する従業員のリストが選択されます。MULTISETキーワードは、これが単一の値とは対照的なリストであることを示します。CAST演算子は、結果セットを適切な型にキャスト(型変換)します。この場合は、ネストした表型employee_list_tにキャストします。

このビューへの問合せでは、それぞれの部門行に、部門番号、名前、住所オブジェクトおよびその部門に所属する従業員のコレクションが入っている部門リストが取得できます。

オブジェクト・ビューのマルチレベル・コレクション

マルチレベル・コレクションもシングルレベル・コレクションも、オブジェクト・ビューで同じ方法で作成し、使用します。異なるのは、マルチレベル・コレクションで、別のレベルのコレクションを作成する必要がある点のみです。

例6-5では、マルチレベル・コレクションが含まれているオブジェクト・ビューを作成します。このビューは、コレクションが何も入っていないフラットなリレーショナル表に基づいています。オブジェクト・ビューを作成する準備作業として、この例で使用するオブジェクト型とコレクション型を作成します。それぞれのリレーショナル表と対応するように、オブジェクト型(たとえば、emp_t)を定義し、その属性の型は、それぞれの表列の型と対応させます。また、従業員型はプロジェクトのネストした表(属性)を持ち、部門型は従業員のネストした表(属性)を持ちます。後者のネストした表は、マルチレベル・コレクションです。CREATE VIEW文の中でCAST-MULTISET演算子を使用して、コレクションを作成します。

例6-5 マルチレベル・コレクションを持つビューの作成

CREATE TABLE depts
( deptno     NUMBER,
deptname   VARCHAR2(20));

CREATE TABLE emps
( ename VARCHAR2(20),
salary     NUMBER,
deptname   VARCHAR2(20));

CREATE TABLE projects
( projname   VARCHAR2(20),
mgr        VARCHAR2(20));

CREATE TYPE project_t AS OBJECT
( projname   VARCHAR2(20),
mgr        VARCHAR2(20));
/
CREATE TYPE nt_project_t AS TABLE OF project_t;
/
CREATE TYPE emp_t AS OBJECT
(  ename      VARCHAR2(20),
salary     NUMBER,
deptname   VARCHAR2(20),
projects   nt_project_t );
/
CREATE TYPE nt_emp_t AS TABLE OF emp_t;
/
CREATE TYPE depts_t AS OBJECT
( deptno     NUMBER,
deptname   VARCHAR2(20),
emps       nt_emp_t );
/
CREATE VIEW v_depts OF depts_t WITH OBJECT IDENTIFIER (deptno) AS
SELECT d.deptno, d.deptname,
CAST(MULTISET(SELECT e.ename, e.salary, e.deptname,
CAST(MULTISET(SELECT p.projname, p.mgr
FROM projects p
WHERE p.mgr = e.ename)
AS nt_project_t)
FROM emps e
WHERE e.deptname = d.deptname)
AS nt_emp_t)
FROM depts d;

オブジェクト・ビューに対するオブジェクト識別子の指定

オブジェクト・ビューの中で、行オブジェクトを指すポインタ(REF)を作成できます。ビューのデータは永続的に格納されるわけではないため、オブジェクト識別子として使用される個々の値を指定する必要があります。オブジェクト識別子を使用すると、オブジェクト・ビューにおけるオブジェクトを、オブジェクト・キャッシュ上で参照し、確保することができます。

このビューがオブジェクト表またはオブジェクト・ビューに基づいている場合には、すでに各行に対応付けられたオブジェクト識別子があり、これを再利用できます。このためには、WITH OBJECT IDENTIFIER句を省略するか、またはWITH OBJECT IDENTIFIER DEFAULT句を指定します。

ただし、行オブジェクトをリレーショナル・データから合成する場合は、他の値セットを選択する必要があります。

主キーに基づいたオブジェクト識別子を指定できます。この場合、行オブジェクトを識別する一意のキーの集合が、そのオブジェクトの識別子になります。値が重複すると、オブジェクト参照時に問題が発生することもあるため、これらの値はビューから選択された行内で一意である必要があります。

関連項目:
主キー・ベースのオブジェクト識別子とシステム生成のオブジェクト識別子の詳細は、「オブジェクト識別子による行オブジェクトの識別」を参照してください。

- WITH OBJECT IDENTIFIER句を使用して作成されたオブジェクト・ビュー
WITH OBJECT IDENTIFIER句を使用して作成されたオブジェクト・ビューは、主キーから導出されたオブジェクト識別子を持ちます。

たとえば、「オブジェクト・ビューのシングルレベル・コレクション」で説明したオブジェクト型dept_tおよびオブジェクト・ビューdept_viewの定義について考えます。

基礎となるリレーショナル表にdeptnoが主キーとして入っているため、各部門行は一意の部門番号を持ちます。このビューでは、deptno列がオブジェクト型のdeptno属性になります。ビュー・オブジェクト内でdeptnoが一意であることがわかれば、これをオブジェクト識別子として指定できます。

- WITH OBJECT IDENTIFIER DEFAULT句を使用して作成されたオブジェクト・ビュー
WITH OBJECT IDENTIFIER DEFAULT句を指定した場合、オブジェクト識別子は、基礎となる表またはビュー定義に応じてはシステム生成または主キー・ベースになります。

関連項目:
「オブジェクト識別子(OID)の記憶域上の考慮点」を参照してください。

オブジェクトを表示するための参照の作成

この例6-2と例6-4の連結された例グループにおいて、dept_viewビューから選択された各オブジェクトは、部門番号の値から導出された一意のオブジェクト識別子を持ちます。リレーショナルの場合、従業員表empの外部キーdeptnoは、部門表deptの主キー値deptnoと一致します。主キー値はdept_view内にオブジェクト識別子を作成するため、emp_viewの外部キー値はdept_viewの主キー値の参照を作成できます。

主キーのオブジェクト参照を合成するには、MAKE_REF演算子を使用します。この演算子は、参照がポイントするビューまたは表の名前および外部キー値のリストをとり、参照されたビューの中の特定のオブジェクトと一致するような参照のオブジェクト識別子部分を作成します。

例6-6では、まず従業員型emp_tを作成し、次にその型に基づいたビューを作成することにより、従業員の番号、名前、給料、および所属部門の参照を持つemp_viewビューを作成します。

例6-6 ビューでのオブジェクトへの参照の作成

-- Requires Ex. 6-2 and Ex. 6-4
-- if you have previously created emp_t, you must drop it
CREATE TYPE emp_t AS OBJECT (
empno    NUMBER,
ename    VARCHAR2(20),
salary   NUMBER,
deptref  REF dept_t);
/
CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(empno)
AS SELECT e.empno, e.empname, e.salary,
MAKE_REF(dept_view, e.deptno)
FROM emp e;

ビューの中のdeptref列に、部門の参照が格納されます。次の簡単な問合せでは、Redwood S市にある部門のすべての従業員を取り出します。

SELECT e.empno, e.salary, e.deptref.deptno
FROM emp_view e
WHERE e.deptref.address.city = 'Redwood S';

EMPNO     SALARY DEPTREF.DEPTNO
---------- ---------- --------------
2       1000            100
1        900            100
4       1500            200
3       1000            200

次のようにMAKE_REFのかわりにREF修飾子を使用してemp_viewを作成しても、dept_viewオブジェクトの参照が取得できる点に注意してください。

例6-7 REFを使用したオブジェクトの問合せ参照

-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6
CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(empno)
AS SELECT e.empno, e.empname, e.salary, REF(d)
FROM emp e, dept_view d
WHERE e.deptno = d.deptno;

例6-7では、dept_viewとemp表はdeptnoキーで結合されます。

例6-6のようにREF修飾子のかわりにMAKE_REF演算子を使用すると、循環参照を作成できるというメリットがあります。たとえば、従業員の部門への参照を持つ従業員のビューを作成する一方で、その部門に所属している従業員への参照のリストを持つ部門のビューを作成することができます。

オブジェクト・ビューが主キー・ベースのオブジェクト識別子を持つ場合、このようなビューへの参照は主キー・ベースになることに注意してください。一方、システム生成のオブジェクト識別子を持つビューへの参照は、システム生成のオブジェクト参照になります。この違いが関係するのは、OCIオブジェクト・キャッシュでオブジェクト・インスタンスを作成し、新しく作成したオブジェクトの参照を取得する必要がある場合のみです。

関連項目:
「オブジェクト・キャッシュ」

合成オブジェクトの場合と同様、永続的に格納される参照をビュー列として選択し、これらを問合せで透過的に使用できます。ただし、ビュー・オブジェクトに対するオブジェクト参照を永続的に格納することはできません。

オブジェクト・ビューを利用した逆リレーションシップのモデル化

オブジェクトを持つビューを使用して、逆リレーションシップをモデル化できます。

1対1リレーションシップ

1対1リレーションシップは、オブジェクトの逆参照を使用してモデル化できます。たとえば、各従業員が専用のデスクトップ・コンピュータを持っているとしましょう。リレーショナル・モデルであれば、コンピュータ表から従業員表へ、または逆の方向で外部キーを使用して、1対1リレーションシップを獲得します。ビューを使用すると、従業員からコンピュータ・オブジェクトへのオブジェクト参照や、コンピュータ・オブジェクトから従業員の参照が行えるように、オブジェクトをモデル化できます。

1対多および多対1リレーションシップ

1対多リレーションシップ(または多対1リレーションシップ)は、オブジェクト参照を使用するか、オブジェクトを埋め込むことでモデル化できます。1対多リレーションシップは、オブジェクトのコレクションまたはオブジェクト参照のコレクションを持つことでモデル化できます。多対1リレーションシップは、オブジェクト参照を使用してモデル化できます。

部門対従業員のケースを検討してみましょう。基礎となるリレーショナル・モデルでは、外部キーが従業員表の中にあります。部門と従業員のリレーションシップは、ビュー内のコレクションを使用してモデル化できます。部門ビューに従業員のコレクションを持たせ、従業員ビューに部門の参照を持たせることができます(または部門値がインライン化できます)。これにより、前方リレーションシップ(従業員から部門へ)と逆リレーションシップ(部門から従業員リストへ)の両方が得られます。また、部門ビューに、従業員オブジェクトを埋め込むかわりに、従業員オブジェクトの参照のコレクションを持たせることも可能です。

オブジェクト・ビューの更新

オブジェクト表に使用するSQL DMLと同じものを使用して、オブジェクト・ビューのデータを更新、挿入および削除できます。あいまいな表現がなければ、オブジェクト・ビューの実表が更新されます。

ビューは常に直接更新できるわけではありません。

ビューの問合せに結合、集合演算子、集計ファンクション、GROUP BYまたはDISTINCT句が含まれている場合、ビューの直接更新はできません。ビューの問合せで、ビューの列が疑似列または式に基づいている場合も、ビューの個々の列を直接更新することはできません。

ビューが直接更新できなくても、INSTEAD OFトリガーを使用して、間接的に更新できます。この操作を行うには、ビューに対して実行するそれぞれのDML文に、INSTEAD OFトリガーを定義します。INSTEAD OFトリガーには、目的の変更をビューで行うために、ビューの基礎となる表に対して実行する必要のある操作をプログラムします。この後、INSTEAD OFトリガーが定義されたDML文を発行すると、関連するトリガーが透過的に実行されます。

関連項目:
INSTEAD OFトリガーの例は、「変更および妥当性チェックを制御するINSTEAD OFトリガーの使用」を参照してください。

注意:
オブジェクト・ビュー階層では、UPDATE文およびDELETE文は、SELECT文と同様に多相性を伴って動作します。つまり、ビューに対して実行されたUPDATEまたはDELETE文で抽出される行の集合には、指定されたビューのすべてのサブビューにある修飾行も明示的に含まれます。

たとえば、Person_vから全員を削除する次の文により、Student_vから学生全員が削除され、Employee_vビューから従業員全員が削除されます。

DELETE FROM Person_v;

サブビューを除外し、影響する行の対象を、指定されたビューに存在する人たちに限定するには、ONLYキーワードを使用します。たとえば、次の文は個人のみ更新し、従業員または学生は更新しません。

UPDATE ONLY(Person_v) SET address = ...

関連項目:
オブジェクト・ビュー階層、およびStudent_vとEmployee_vを定義する例は、「オブジェクト・ビューの階層」を参照してください。

ビューにおけるネストした表列の更新

ネストした表を更新するには、新しい要素を挿入したり、既存の要素を更新または削除します。ビューの場合と同様に、仮想または合成のネストした表列は、通常は更新できません。この問題に対処するために、この列の上にINSTEAD OFトリガーを作成できます。

(ビューの)ネストした表列に対して定義されたINSTEAD OFトリガーは、列を変更するときに起動します。親である行の更新によってコレクション全体が置換される場合は、ネストした表列のINSTEAD OFトリガーは起動されないため注意してください。

変更および妥当性チェックを制御するINSTEAD OFトリガーの使用

INSTEAD OFトリガーを使用することで、他の方法では更新できない複雑なビューを更新できます。また制約の施行、権限のチェック、DML文の妥当性チェックにも、このトリガーを使用できます。これらのトリガーを使用すると、オブジェクト・ビューを介して作成されたオブジェクトに挿入、更新および削除が行われた結果としての変更を制御できます。

たとえば、ある部門の従業員の数を10以下とするという条件を施行する場合は、従業員ビュー用のINSTEAD OFトリガーを記述できます。ビューは更新できるため、DML文の実行にトリガーは必要ありませんが、制約を施行するにはトリガーが必要です。

例6-8に、SQL文を使用してトリガーを実装する方法を示します。

例6-8 ビューのINSTEAD OFトリガーの作成

-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6
CREATE TRIGGER emp_instr INSTEAD OF INSERT on emp_view
FOR EACH ROW
DECLARE
dept_var dept_t;
emp_count integer;
BEGIN
-- Enforce the constraint
-- First get the department number from the reference
UTL_REF.SELECT_OBJECT(:NEW.deptref, dept_var);

SELECT COUNT(*) INTO emp_count
FROM emp
WHERE deptno = dept_var.deptno;
IF emp_count < 9 THEN
-- Do the insert
INSERT INTO emp (empno, empname, salary, deptno)
VALUES (:NEW.empno, :NEW.ename, :NEW.salary, dept_var.deptno);
END IF;
END;
/

関連項目:
「オブジェクト表のトリガー」

オブジェクト・モデルのリモート表への適用

リモート表は、オブジェクト表のように直接アクセスできませんが、オブジェクト・ビューでは、あたかもオブジェクト表であるかのように、リモート表にアクセスできます。

ワシントンD.C.およびシカゴに支店を持つ会社について考えてみます。各支店に、従業員表があります。ワシントンの本社には、すべての部門のリストを持つ部門表があります。組織全体のビューを作成するには、個々のリモート表の上にビューを作成し、次に組織全体のビューを作成します。

このためには、次の手順を実行する必要があります。

- listener.oraのエントリ((ADDRESS=(PROTOCOL=tcp) (HOST=stadv07.us.example.com)(PORT=1640))など)を更新します。

- tnsnames.oraにエントリ(chicago=(DESCRIPTION= (ADDRESS=(PROTOCOL=ipc)(KEY=linux)) (CONNECT_DATA=(SERVICE_NAME=linux.regress.rdbms.dev.us.example.com)))など)を追加します。

- 例6-9に示すようなCREATE DATABASE LINKコードを入力します。

例6-9では、各従業員表のオブジェクト・ビューを作成してから、グローバル・ビューを作成しています。

例6-9 リモート表にアクセスするためのオブジェクト・ビューの作成

-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6
-- Example requires DB links, such as these, modify for your use and uncomment
-- CREATE DATABASE LINK chicago CONNECT TO hr IDENTIFIED BY hr USING 'inst1';
-- CREATE DATABASE LINK washington CONNECT TO hr IDENTIFIED BY hr USING 'inst1';
CREATE VIEW emp_washington_view (eno, ename, salary, job)
AS SELECT e.empno, e.empname, e.salary, e.job
FROM emp@washington e;

CREATE VIEW emp_chicago_view (eno, ename, salary, job)
AS SELECT e.empno, e.empname, e.salary, e.job
FROM emp@chicago e;

CREATE VIEW orgnzn_view OF dept_t WITH OBJECT IDENTIFIER (deptno)
AS SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr,
CAST( MULTISET (
SELECT e.eno, e.ename, e.salary, e.job
FROM emp_washington_view e)
AS employee_list_t) AS emp_list
FROM dept d
WHERE d.deptcity = 'Washington'
UNION ALL
SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr,
CAST( MULTISET (
SELECT e.eno, e.ename, e.salary, e.job
FROM emp_chicago_view e)
AS employee_list_t) AS emp_list
FROM dept d
WHERE d.deptcity = 'Chicago';

このビューは、各部門のすべての従業員のリストを持ちます。従業員は複数の部門に所属できないため、UNION ALL句が使用されています。

オブジェクト・ビューにおける複雑なリレーションシップの定義

オブジェクト・ビューには、MAKE_REF演算子を使用して、循環参照を定義できます。つまり、view_Aがview_Bを参照して、view_Bがview_Aを参照することもできます。これにより、リレーショナル・データで構成されるグラフのように複雑な構造を、オブジェクト・ビューが合成できるようになります。

たとえば、部門および従業員の例の場合、部門オブジェクトに従業員のリストが含まれています。領域を節約するために、部門オブジェクト内のすべての従業員を具体化せずに、従業員オブジェクトの参照を、部門オブジェクト内部に入れてみます。従業員オブジェクトへの参照を構成(確保)し、後でドット表記法を使用してこの参照に従い、従業員情報を抽出できます。

従業員オブジェクトはすでに従業員の所属部門への参照を持っているため、このモデルでのオブジェクト・ビューには、部門ビューと従業員ビューの間の循環参照が含まれます。

オブジェクト・ビュー間の循環参照は、次の2通りの方法で作成できます。

注意:
循環参照の作成方法ではいずれも、「循環参照を示す表および型」に示されている設定を実行する必要があります。

- 2つ目のビューを作成した後、最初のビューを作成する

1. ビューBへの参照を持たないビューAを作成します。

2. ビューAへの参照を含むビューBを作成します。

3. ビューAをビューBの参照を含む新しい定義で置換します。

「方法1: 2つ目のビューを作成した後、最初のビューを再作成する」の例を参照してください。

- FORCEキーワードを使用して最初のビューを作成する

1. FORCEキーワードを使用して、ビューBへの参照を持つビューAを作成します。

2. ビューAの参照を持つビューBを作成します。ビューAを使用すると、妥当性チェックが行われ、再コンパイルされます。

「方法2: FORCEキーワードを使用して最初のビューを作成する」の例を参照してください。

方法2の方が、手順が簡単ですが、ビューの作成時に、FORCEキーワードによりエラーが隠される可能性があります。ビュー作成中にエラーが発生したかどうかを確認するには、USER_ERRORSカタログ・ビューを問い合せる必要があります。ビュー作成文の中にエラーがないことが保証されている場合にのみ、この方法を使用してください。

また、使用時にエラーによってビューが再コンパイルできない場合は、ALTER VIEW COMPILEコマンドを使用し、ビューを手動で再コンパイルする必要があります。

循環ビュー参照の作成では、いずれの方法を使用する場合も、あらかじめ次に説明する設定を実行してください。

循環参照を示す表および型

まず、リレーショナル表および対応付けられたオブジェクト型を設定する必要があります。表にオブジェクトが入っていても、この表はオブジェクト表ではありません。データ・オブジェクトにアクセスするために、後でオブジェクト・ビューを作成します。

emp表には、従業員情報が入っています。

例6-10 循環参照を示すemp表の作成

CREATE TABLE emp
(  empno    NUMBER PRIMARY KEY,
empname  VARCHAR2(20),
salary   NUMBER,
deptno   NUMBER );

-- first create a dummy, that is, incomplete, department type, so emp_t type
-- created later will succeed

CREATE TYPE dept_t;
/

-- Create the employee type with a reference to the department, dept_t:
CREATE TYPE emp_t AS OBJECT
( eno NUMBER,
ename VARCHAR2(20),
salary  NUMBER,
deptref REF dept_t );
/

-- Represent the list of references to employees as a nested table:
CREATE TYPE employee_list_ref_t AS TABLE OF REF emp_t;
/

-- Create the department table as a relational table
CREATE TABLE dept
(   deptno        NUMBER PRIMARY KEY,
deptname      VARCHAR2(20),
deptstreet    VARCHAR2(20),
deptcity      VARCHAR2(10),
deptstate     CHAR(2),
deptzip       VARCHAR2(10) );

-- Create object types that map to columns from the relational tables:
CREATE TYPE address_t AS OBJECT
( street        VARCHAR2(20),
city         VARCHAR2(10),
state        CHAR(2),
zip          VARCHAR2(10));
/

-- Fill in the definition for dept_t, the incomplete type you previously created:
CREATE OR REPLACE TYPE dept_t AS OBJECT
( dno           NUMBER,
dname         VARCHAR2(20),
deptaddr      address_t,
empreflist    employee_list_ref_t);
/

例6-10に示すように、emp表を作成してから、ダミーの部門型dept_tを作成する必要があります(これにより、作成したemp_t型が正常に機能できるようになります)。その後、dept_tへの参照を持つemp_tを作成します。ネストした表employee_list_ref_tとして従業員への参照のリストを作成し、部門表deptを作成します。次に、リレーショナル表にマップする列を持つオブジェクト型address_tを作成し、最後に不完全なdept_tの定義に埋め込みます。

使用できるデータ例を次に示します。

insert into emp values(1,'John','900',100);
insert into emp values(2,'james','1000',100);
insert into emp values(3,'jack',2000,200);

循環参照を持つオブジェクト・ビューの作成

前の項で基礎となるリレーショナル表が完成したので、今度はこのリレーショナル表にオブジェクト・ビューを作成します。

方法1: 2つ目のビューを作成した後、最初のビューを再作成する

まず、deptref列にNULLを持つ従業員ビューを作成します。後で、その列を参照に変えることができます。

次に、従業員オブジェクトへの参照を含む部門ビューを作成します。これにより、従業員オブジェクト全体を含めるのではなく、従業員オブジェクトへの参照のリストを作成します。

次に、部門ビューへの参照を持つ従業員ビューを再作成します。

例6-11 循環参照を持つオブジェクト・ビューの作成、方法1

-- Requires Ex. 6-10
CREATE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno)
AS SELECT e.empno, e.empname, e.salary, NULL
FROM emp e;

-- create department view, including references to the employee objects
CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER(dno)
AS SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip),
CAST( MULTISET (
SELECT MAKE_REF(emp_view, e.empno)
FROM emp e
WHERE e.deptno = d.deptno)
AS employee_list_ref_t)
FROM dept d;

CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno)
AS SELECT e.empno, e.empname, e.salary,
MAKE_REF(dept_view, e.deptno)
FROM emp e;

これでビューが作成されました。

方法2: FORCEキーワードを使用して最初のビューを作成する

ビューを作成する文に構文エラーがないという確信があれば、FORCEキーワードを使用して、他のビューを存在させずに、最初のビューを強制的に作成できます。

まず、この時点で存在しない部門ビューへの参照を含む従業員ビューを作成します。部門ビューが適切に作成されるまで、このビューの問合せは実行できません。

次に、従業員オブジェクトへの参照を含む部門ビューを作成します。emp_viewがすでに存在するため、ここでFORCEキーワードを使用する必要はありません。これにより、部門ビューの問合せを実行し、ネストした表empreflistからの従業員参照を解除することで従業員オブジェクトを取得できます。

注意:
すでに例6-11を実行した場合は、作成したビューを削除してから例6-12を実行してください。

例6-12 FORCEを持つビューの作成、方法2

-- Requires Ex. 6-10
-- create employee view
CREATE OR REPLACE FORCE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno)
AS SELECT e.empno, e.empname, e.salary,
MAKE_REF(dept_view, e.deptno)
FROM emp e;

-- create a department view that includes references to the employee objects
CREATE OR REPLACE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER(dno)
AS SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip),
CAST( MULTISET (
SELECT MAKE_REF(emp_view, e.empno)
FROM emp e
WHERE e.deptno = d.deptno)
AS employee_list_ref_t)
FROM   dept d;

-- Querying with DEREF method
SELECT DEREF(e.COLUMN_VALUE)
FROM TABLE( SELECT e.empreflist FROM dept_view e WHERE e.dno = 100) e;

COLUMN_VALUEは、スカラーのネストした表の中のスカラー値を表す特別な名前です。この場合、COLUMN_VALUEはネストした表empreflistの中にある従業員オブジェクトの参照を示しています。

名前がJohnで始まるすべての従業員の従業員番号のみにアクセスすることも可能です。

例6-13 COLUMN_VALUEを使用した問合せ

-- Requires Ex. 6-10 and 6-12
SELECT e.COLUMN_VALUE.eno
FROM TABLE(SELECT e.empreflist FROM dept_view e WHERE e.dno = 100) e
WHERE e.COLUMN_VALUE.ename like 'John%';

表形式で出力するには、部門表をネストした表の項目と結合し、参照のリストのネストを解除します。

例6-14 COLUMN_VALUEを使用した問合せ、参照のネスト解除

-- Requires Ex. 6-10 and 6-12SELECT d.dno, e.COLUMN_VALUE.eno, e.COLUMN_VALUE.ename
FROM dept_view d, TABLE(d.empreflist) e
WHERE e.COLUMN_VALUE.ename like 'John%'
AND d.dno = 100;

最後に、dept_viewのかわりにemp_viewを使用するように、前述の問合せを書きなおし、ビュー間をナビゲートする方法を紹介します。

例6-15 COLUMN_VALUEを使用した問合せ、emp_viewの問合せ

-- Requires Ex. 6-10 and 6-12
SELECT e.deptref.dno, DEREF(f.COLUMN_VALUE)
FROM emp_view e, TABLE(e.deptref.empreflist) f
WHERE e.deptref.dno = 100
AND f.COLUMN_VALUE.ename like 'John%';

オブジェクト・ビューの階層

オブジェクト・ビュー階層は、オブジェクト・ビューの集合で、型階層内の様々な型が、それぞれのオブジェクト・ビューの基になっています。ビュー階層内のサブビューは、型階層内のサブタイプがスーパータイプの下に作成される場合と同じ方法で、スーパービューの下に作成されます。

ビュー階層内のそれぞれのオブジェクト・ビューは、1つの型のオブジェクトと一緒に移入されますが、任意のビューについての問合せでは、そのサブビューも暗黙的に扱います。このように、オブジェクト・ビュー階層により、一定のレベルまたはそれ以上のレベルに特化されたオブジェクトの多相集合を返す問合せを、簡単に組み立てられます。

person_typをルートとする、次のような型階層について考えてみます。

図6-1 オブジェクト型階層

オブジェクト・ビューをそれぞれの型に基づいて作成し、この型階層に基づいてオブジェクト・ビュー階層を作成しておくと、目的の特化レベルと対応するオブジェクト・ビューの問合せができます。たとえば、student_typのビューについて問い合せ、学生(定時制の学生を含む)のみ入っている結果セットを取得できます。

型階層内のいずれの型も、オブジェクト・ビュー階層のルート・ビューの基として使用できます。つまり、オブジェクト・ビュー階層をルート型から組み立てる必要はありません。また、オブジェクト・ビュー階層を型階層の各リーフまで拡張したり、すべてのブランチを範囲に入れる必要もありません。ただし、下位に介在するサブタイプは省略できません。いずれのサブビューも、直系スーパービューの型の直系サブタイプに基づく必要があります。

型が兄弟関係にあるサブタイプを2つ以上持てるように、オブジェクト・ビューも兄弟関係にあるサブビューを2つ以上持てます。ただし、任意の型に基づくサブビューが関与できるのは、1つのオブジェクト・ビュー階層のみです。2つの異なるオブジェクト・ビュー階層に、同じサブタイプに基づく1つのサブビューが存在することはありません。

サブビューはスーパービューからオブジェクト識別子(OID)を継承します。任意のサブビューに、OIDを明示的に指定することは許可されません。

ルート・ビューでは、WITH OBJECT ID句を使用して、オブジェクト識別子を明示的に指定できます。OIDがシステムによって生成される場合、またはルート・ビューに句を指定しない場合、サブビューを作成できるのは、同様にシステム生成のOIDを使用する表またはビューがルート・ビューの基になっている場合のみです。

ビューの基礎となる問合せにより、ビューが更新可能かどうかが決まります。ビューの問合せに、結合、集合演算子、集計ファンクション、GROUP BY句、DISTINCT句、疑似列または式を何も入れないというのが、ビューを更新可能にするための条件です。サブビューについても同じ条件が適用されます。

ビューが更新可能でなくても、適切なDML処理を実行するためのINSTEAD OFトリガーが定義できます。サブビューはINSTEAD OFトリガーを継承しない点に注意してください。

ビュー階層内のすべてのビューは、同じスキーマに所属する必要があります。

注意:
インスタンス化不可の型のビューを作成できます。インスタンス化不可の型は、インスタンスを持つことはできないので、このような型のオブジェクト・ビューを作成しても意味がありません。ただし、インスタンス化不可の型は、インスタンス化可能なサブタイプを持つことができます。インスタンス化不可の型のオブジェクト・ビューを作成できるため、インスタンス化不可の型が含まれている型階層をオブジェクト・ビュー階層の基にすることができます。

オブジェクト・ビュー階層の作成

オブジェクト・ビュー階層は、ルート・ビューの下にサブビューを作成して、構築します。このためには、例6-17のようにCREATE VIEW文でUNDERキーワードを使用します。

基礎となる様々な記憶域モデルが、同じオブジェクト・ビュー階層の基になることもあります。つまり、基礎となる表の様々なレイアウトや設計により、同じオブジェクト・ビュー階層が作成される可能性があるということです。基礎となる記憶域モデルの設計は、オブジェクト・ビュー階層のパフォーマンスや更新可能性に影響を与えます。

この項では、考えられる3種類の記憶域モデルを示します。最初のフラット・モデルの場合、オブジェクト・ビュー階層内のすべてのビューの基は、同じ表です。2番目の水平モデルの場合、それぞれのビューは、それぞれ別の表と1対1で対応します。3番目の垂直モデルの場合は、結合を使用してビューが構成されます。

これらの記憶域モデルを実行するには、まず例6-16に示すような型を作成します。

例6-16 記憶域モデル例に使用する型の作成

CREATE TYPE person_typ AS OBJECT
( ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100)) NOT FINAL;/

CREATE TYPE student_typ UNDER person_typ
( deptid NUMBER,
major VARCHAR2(30)) NOT FINAL;/

CREATE TYPE employee_typ UNDER person_typ
( empid NUMBER,
mgr VARCHAR2(30));/

この項の内容は次のとおりです。

- フラット・モデル

- 水平モデル

- 垂直モデル

フラット・モデル

フラット・モデルの場合、オブジェクト・ビュー階層内のすべてのビューの基となるのは、同じ表です。次に例に示すAllPersonsという1つの表には、person_typ、student_typおよびemployee_typのすべての属性の列が格納されます。

図6-2 オブジェクト・ビュー階層のフラット記憶域モデル

それぞれの行の型は、typeid列により識別されます。これらの有効な値は、例6-16で作成した型(1 = person_typ、2 = student_typ、 3 = employee_typ)です。

例6-17では、表AllPersonsを作成してから、オブジェクト・ビュー階層を構成するビューを作成します。

例6-17 オブジェクト・ビュー階層の作成

-- Requires Ex. 6-16
CREATE TABLE AllPersons
( typeid NUMBER(1),
ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100),
deptid NUMBER,
major VARCHAR2(30),
empid NUMBER,
mgr VARCHAR2(30));

CREATE VIEW Person_v OF person_typ
WITH OBJECT OID(ssn) AS
SELECT ssn, name, address
FROM AllPersons
WHERE typeid = 1;

CREATE VIEW Student_v OF student_typ UNDER Person_v
AS
SELECT ssn, name, address, deptid, major
FROM AllPersons
WHERE typeid = 2;

CREATE VIEW Employee_v OF employee_typ UNDER Person_v
AS
SELECT ssn, name, address, empid, mgr
FROM AllPersons
WHERE typeid = 3;

単純である、という点がフラット・モデルの利点です。また、フラット・モデルが、索引や制約への対応に支障をきたす原因になることはありません。このモデルのデメリットは、次のとおりです。

- 1つの表に格納できる列は1000以下のため、フラット・モデルでは、オブジェクト・ビュー階層に格納できる列の合計数が、1000列に制限されます。

- 表の各列には、オブジェクト・ビューの型に属さないすべての属性のかわりにNULLが入ってしまいます。このようにNULLが後続しない状態は、パフォーマンスを低下させる可能性があります。

水平モデル

水平モデルの場合、それぞれのビューまたはサブビューの基になるのは、異なる表です。例に示す表はリレーショナル表ですが、これらの表は、列の代入性が無効になるオブジェクト表になる場合もあります。

図6-3 オブジェクト・ビュー階層の水平記憶域モデル

例6-18では、表を作成してから、これらの表に基づくビューを作成します。

例6-18 表の水平モデルの作成

-- Requires Ex. 6-16 and Ex. 6-17
CREATE TABLE only_persons
( ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100));

CREATE TABLE only_students
( ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100),
deptid NUMBER,
major VARCHAR2(30));

CREATE TABLE only_employees
( ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100),
empid NUMBER,
mgr VARCHAR2(30));

CREATE OR REPLACE VIEW Person_v OF person_typ
WITH OBJECT OID(ssn) AS
SELECT *
FROM only_persons;

CREATE OR REPLACE VIEW Student_v OF student_typ UNDER Person_v
AS
SELECT *
FROM only_students;

CREATE OR REPlACE VIEW Employee_v OF employee_typ UNDER Person_v
AS
SELECT *
FROM only_employees;

水平モデルを使用すると、非常に効率的なのは、次のような構成の問合せです。

例6-19 ビューの水平モデルの問合せ

-- Requires Ex. 6-16 and Ex. 6-17
-- add the following data
insert into only_persons values(1234,'John','abc');
insert into only_students values(1111,'James','abc',100,'CS');
insert into only_employees values(2222,'jack','abc',400,'Juliet');

SELECT VALUE(p) FROM Person_v p
WHERE VALUE(p) IS OF (ONLY student_typ);

OUTPUT:
VALUE(P)(SSN, NAME, ADDRESS)
--------------------------------------------------------------------------------
STUDENT_TYP(1111, 'James', 'abc', 100, 'CS')

このような問合せでは、特定の型のオブジェクトをすべて取得するために、1つの物理表にアクセスするのみですみます。このモデルのデメリットは、SELECT * FROM viewのような問合せでは、基礎となるすべての表に対してUNIONを実行し、指定されたビューの列に対してのみ行を投影する必要があることです。(「階層内のビューの問合せ」を参照してください。)また、属性(および一意制約)についての索引は複数の表をまたがる必要がありますが、現在この機能はサポートされていません。

垂直モデル

垂直モデルの場合、階層内のそれぞれのビューと対応する物理表が存在しますが、物理表に格納されるのは、対応するサブタイプに固有の属性のみです。

図6-4 オブジェクト・ビュー階層の垂直記憶域モデル

例6-20では、表を作成してから、対応するビューを作成します。

例6-20 表およびビューの垂直モデルの作成

CREATE TABLE all_personattrs
( typeid NUMBER,
ssn NUMBER,
name VARCHAR2(30),
address VARCHAR2(100));

CREATE TABLE all_studentattrs
( ssn NUMBER,
deptid NUMBER,
major VARCHAR2(30));

CREATE TABLE all_employeeattrs
( ssn NUMBER,
empid NUMBER,
mgr VARCHAR2(30));

CREATE OR REPLACE VIEW Person_v OF person_typ
WITH OBJECT OID(ssn) AS
SELECT ssn, name, address
FROM all_personattrs
WHERE typeid = 1;

CREATE OR REPLACE VIEW Student_v OF student_typ UNDER Person_v
AS
SELECT x.ssn, x.name, x.address, y.deptid, y.major
FROM all_personattrs x, all_studentattrs y
WHERE x.typeid = 2 AND x.ssn = y.ssn;

CREATE OR REPLACE VIEW Employee_v OF employee_typ UNDER Person_v
AS
SELECT x.ssn, x.name, x.address, y.empid, y.mgr
FROM all_personattrs x, all_employeeattrs y
WHERE x.typeid = 3 AND x.ssn = y.ssn;

垂直モデルでは、SELECT * FROM root_viewのような問合せが効率的に処理され、また、個々の属性に索引を付けたり、属性に一意制約を付けることができます。ただし、型のインスタンスを再作成するには、それぞれのレベルについて、階層のルートから型を削除するオブジェクト識別子(OID)の結合を実行する必要があります。

階層内のビューの問合せ

オブジェクト・ビュー階層内の任意のビューまたはサブビューに対し、問合せを実行できます。問合せにより戻されるのは、問い合せたビューの宣言された型の行と、その型のサブタイプの行です。たとえば、person_typ型階層が基になっているオブジェクト・ビュー階層では、person_typのビューを問い合せて、学生や従業員を含む個人全員が格納されている結果セットを取得したり、student_typのビューを問い合せて、学生(定時制の学生を含む)のみ格納されている結果セットを取得できます。

問合せのSELECT構文のリストには、オブジェクト・インスタンスを戻すREF()やVALUE()のようなファンクションを含めるか、またはperson_typのnameやssn属性のようなビューの宣言された型のオブジェクト属性を指定できます。

オブジェクト・インスタンスを戻すためにファンクションを指定すると、問合せにより多相結果セットが戻されます。つまり、ビューの宣言された型のインスタンスと、その型のサブタイプのインスタンスのどちらも戻されます。

たとえば、次の問合せでは、あらゆる型の個人、従業員および学生のインスタンスのみでなく、これらのインスタンスREFも戻されます。

例6-21 REFと値での問合せ

-- Requires Ex. 6-20
insert into all_personattrs values(1,1111,'John','abc');
insert into all_personattrs values(2,2222,'Jack','def');
insert into all_personattrs values(3,3333,'James','ghi');
insert into all_studentattrs values(2222,100,'CS');
insert into all_employeeattrs values(3333,444,'Julia');
SELECT REF(p), VALUE(p) FROM Person_v p;

OUTPUT:
REF(P)
--------------------------------------------------------------------------------
VALUE(P)(SSN, NAME, ADDRESS)
--------------------------------------------------------------------------------
00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000
090600812A00078401FE0000000B03C20C0C00000000000000000000000000000000000000
PERSON_TYP(1111, 'John', 'abc')

00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000
090600812A00078401FE0000000B03C2222200000000000000000000000000000000000000
EMPLOYEE_TYP(3333, 'James', 'ghi', 444, 'Julia')

00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000

REF(P)
--------------------------------------------------------------------------------
VALUE(P)(SSN, NAME, ADDRESS)
--------------------------------------------------------------------------------
090600812A00078401FE0000000B03C2171700000000000000000000000000000000000000
STUDENT_TYP(2222, 'Jack', 'def', 100, 'CS')

ビューの宣言された型の個々の属性をSELECT構文のリストに指定した場合、またはSELECT *を実行した場合も、ビューの宣言された型およびこの型のサブタイプの行が戻されます。ただし、これらの行が投影される先は、ビューの宣言された型の属性の列で、使用されるのは、これらの列のみです。つまり、サブタイプを表現する対象は、ビューの宣言された型からサブタイプが継承した属性、およびサブタイプがビューの宣言された型と共有する属性のみです。

たとえば、次の問合せでは、個人全員の行およびあらゆる型の従業員および学生の行が戻されますが、結果に使用されるのは、person_typの属性(name、ssnおよびaddress)の列のみです。student_typのdeptid属性などサブタイプに追加された属性の行は、何も表示されません。

SELECT * FROM Person_v;

結果からサブビューを除外するには、ONLYキーワードを使用します。ONLYキーワードにより、選択対象が、問合せ対象のビューの宣言された型に限定されます。

SELECT VALUE(p) FROM ONLY(Person_v) p;

ビュー階層についての操作の権限

通常、サブビューを持つビューについての問合せで要求されるのは、参照対象のビューについてのSELECT権限のみで、サブビューについての明示的な権限は要求されません。次に示す問合せでは、Person_vについてのSELECT権限のみ要求され、このビューのサブビューについての権限は要求されません。

SELECT * FROM Person_v;

ただし、サブタイプの属性として追加されていても、ルート型では使用しない属性を選択する問合せの場合は、サブビューについてのSELECT権限も要求されます。このようなサブタイプ属性には、別のアクセス権限を適度に必要とする機密情報が格納されている可能性があります。

次に示す問合せでは、オブジェクト・インスタンスが選択され、その結果、サブタイプのすべての属性が取り出されるため、Person_v、Student_v、Employee_v(およびPerson_vのサブビュー)についてのSELECT権限が要求されます。

SELECT VALUE(p) FROM Person_v p;

ビュー階層全体についてのSELECT権限を付与する処理を簡素化するには、HIERARCHYオプションが使用できます。ビューについてのSELECT権限をユーザーに付与するときに、HIERARCHYオプションを指定すると、現在および将来存在するビューのすべてのサブビューについてのSELECT権限も暗黙的に付与されます。次に例を示します。

GRANT SELECT ON Person_v TO user WITH HIERARCHY OPTION;

サブビューに属する行を除外する問合せには、すべてのサブビューについてのSELECT権限も要求されます。その理由は、インスタンスの最も狭い意味での型にのみ属している行の情報は、機密情報の可能性があり、すべての行をサブビューから除外する問合せ(次に示すような問合せ)の場合は、サブビューについてのSELECT権限が要求されるためです。

SELECT * FROM ONLY(Person_v);

7 Oracleオブジェクトの管理

この章では、Oracleオブジェクトがデータベースの他の部分と関連してどのように機能するか、またDML操作およびDDL操作をどのように実行するかについて説明します。内容は次のとおりです。

- オブジェクト型およびそれらのメソッドの権限

- 型依存性

- オブジェクト型のシノニム

- パフォーマンス・チューニング

オブジェクト型およびそれらのメソッドの権限

オブジェクト型に対する権限は、システム・レベルおよびスキーマ・オブジェクト・レベルで存在します。

この項の内容は次のとおりです。

- オブジェクト型のシステム権限

- スキーマ・オブジェクト権限

- 新しい型または表での型の使用

- 例: オブジェクト型の権限

- オブジェクト、型および表のアクセス権限

オブジェクト型のシステム権限

Oracleデータベースでは、オブジェクト型に次のシステム権限を定義します。

- CREATE TYPE: 自分のスキーマにオブジェクト型を作成できます。

- CREATE ANY TYPE: 任意のスキーマにオブジェクト型を作成できます。

- ALTER ANY TYPE: 任意のスキーマ内のオブジェクト型を変更できます。

- DROP ANY TYPE: 任意のスキーマ内のオブジェクト型を削除できます。

- EXECUTE ANY TYPE: 任意のスキーマ内のオブジェクト型を使用および参照できます。

- UNDER ANY TYPE: 任意のNOT FINALオブジェクト型の下にサブタイプを作成できます。

- UNDER ANY VIEW: 任意のオブジェクト・ビューの下にサブビューを作成できます。

次のロールが有用です。

- RESOURCEロールには、CREATE TYPEシステム権限が含まれます。

- DBAロールには、前述のすべての権限が含まれます。

スキーマ・オブジェクト権限

オブジェクト型には、2つのスキーマ・オブジェクト権限が適用されます。

- EXECUTE権限があると、その型を次のように使用できます。

- 表の定義

- リレーショナル表の列の定義

- オブジェクト型の変数またはパラメータの宣言

EXECUTEは、コンストラクタなどの型のメソッドを起動します。

メソッド実行および対応する権限は、ストアドPL/SQLプロシージャのものと同じです。

- UNDERは、権限が与えられた型またはビューの下にサブタイプまたはサブビューを作成します。
直系のスーパータイプまたはスーパービューについてUNDER権限をWITH GRANT OPTION付きで持っている権限付与者のみ、サブタイプまたはサブビューに対するUNDER権限が付与されます。

WITH HIERARCHY OPTION句は、オブジェクトのすべてのサブタイプについて指定されたオブジェクト権限を付与します。このオプションが意味を持つのは、オブジェクト・ビュー階層内のオブジェクト・ビューにSELECTオブジェクト権限が付与されている場合のみです。この場合、権限が付与されているビューのサブビューすべてに、権限が適用されます。

新しい型または表での型の使用

次の場合は、前述の項で説明した権限の他に、特定の権限が必要です。

- 別のユーザーが作成した型を使用する型または表を作成する場合

- 新しく作成した型または表の使用権限を別のユーザーに付与する場合

EXECUTE ANY TYPEシステム権限、または新しい型または表を定義するために使用される型に対するEXECUTEオブジェクト権限が必要です。ロールを介してではなく、これらの権限を明示的に付与しておく必要があります。

新しい型または表へのアクセス権限を他のユーザーに付与するには、Grantオプションを含む適切なEXECUTEオブジェクト権限、またはオプションWITH ADMIN OPTIONを含むEXECUTE ANY TYPEシステム権限が必要です。ロールを介してではなく、これらの権限を明示的に付与しておく必要があります。

例: オブジェクト型の権限

例7-1では、3つのユーザーまたはスキーマUSER1、USER2およびUSER3を作成し、CREATE SESSIONおよび RESOURCEロールを付与します。この章の後続の例でこれらのスキーマを使用する場合があります。

この例では、複数のパスワードを作成および使用する必要があります。例を実行する場合、最初にSQLコードに対してこれらの変更を行います。

注意:
簡略化のため、この例では、デプロイされたシステムで通常使用するパスワード管理技法を実行しません。本番環境では、Oracle Databaseパスワード管理ガイドラインに従って、サンプル・アカウントを無効にしてください。パスワード管理ガイドラインおよび他のセキュリティ推奨事項は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

例7-1 ユーザー・スキーマの作成

-- Requires passwords
CONNECT SYSTEM
-- Enter password
CREATE USER user1 PROFILE default
IDENTIFIED BY password DEFAULT TABLESPACE example ACCOUNT UNLOCK;
GRANT CREATE SESSION TO user1;
GRANT RESOURCE TO user1;
GRANT CREATE SYNONYM TO user1;
GRANT CREATE PUBLIC SYNONYM TO user1;
GRANT DROP PUBLIC SYNONYM TO user1;
CREATE USER user2 PROFILE default
IDENTIFIED BY password DEFAULT TABLESPACE example ACCOUNT UNLOCK;
GRANT CREATE SESSION TO user2;
GRANT RESOURCE TO user2;
CREATE USER user3  PROFILE default
IDENTIFIED BY password DEFAULT TABLESPACE example ACCOUNT UNLOCK;
GRANT CREATE SESSION TO user3;
GRANT RESOURCE TO user3;

例7-2ではパスワードの入力が必要で、USER1は、USER1スキーマのCREATEおよびGRANTデータ定義言語(DDL)文を実行します。

例7-2 オブジェクト型の権限の付与

-- Requires Ex. 7-1 and the input of a password
CONNECT user1
-- Enter password

CREATE TYPE type1 AS OBJECT ( attr1 NUMBER );
/
CREATE TYPE type2 AS OBJECT ( attr2 NUMBER );
/
GRANT EXECUTE ON type1 TO user2;
GRANT EXECUTE ON type2 TO user2 WITH GRANT OPTION;

例7-3で、USER2は、USER2スキーマのCREATE DDL文を実行します。

例7-3 USER2スキーマのDDL文の実行

-- Requires Ex. 7-1, 7-2 and password input
CONNECT user2
-- Enter password
CREATE TABLE tab1 OF user1.type1;
CREATE TYPE type3 AS OBJECT ( attr3 user1.type2 );
/
CREATE TABLE tab2 (col1 user1.type2 );

例7-4では、例7-2の最後の行でUSER2に対してUSER1のTYPE2にGRANTオプションを使用したEXECUTE権限が付与され、例7-3でattr3 user1.type2を使用してオブジェクトとしてtype3が作成されたため、最初の2つの文が正常に実行されます。

ただし、USER2にUSER1.TYPE1のGRANTオプションを使用したEXECUTE権限が付与されていないため、例7-4の最後の付与は失敗します。

例7-4 USER3への付与の実行

-- Requires Ex. 7-1, 7-2, and 7-3
GRANT EXECUTE ON type3 TO user3;
GRANT SELECT ON tab2 TO user3;

-- Privileges on Object Types
GRANT SELECT ON tab1 TO user3 -- incorrect statement;

例7-5で、USER3には、次の処理を実行するために必要な権限があります。

例7-5 表および型の作成

-- Requires Ex. 7-1, 7-2, 7-3, and 7-4
CONNECT user3
-- Enter password
CREATE TYPE type4 AS OBJECT (attr4 user2.type3);
/
CREATE TABLE tab3 OF type4;

オブジェクト、型および表のアクセス権限

オブジェクト型はEXECUTE権限のみを使用しますが、オブジェクト表はリレーショナル表と同じ次のすべての権限を使用します。

- SELECT: 表から1つのオブジェクトおよびその属性にアクセスできます。

- UPDATE: 表内のオブジェクトの属性を変更できます。

- INSERT: 表に新しいオブジェクトを追加できます。

- DELETE: 表からオブジェクトを削除できます。

同様の表権限および列権限が、オブジェクト型の表列の使用を規制します。

オブジェクト表の列を選択するには、オブジェクト表の型に対する権限は必要ありません。ただし、行全体を選択するには必要です。

例7-6に示すスキーマと問合せを考えてみます。

例7-6 型へのアクセスのSELECT権限

-- Requires Ex. 7-1, 7-2, 7-3, 7-4, and 7-5
CREATE TYPE emp_type AS OBJECT (
eno     NUMBER,
ename   VARCHAR2(36));
/
CREATE TABLE emp OF emp_type; // an object table
GRANT SELECT on emp TO user1;
SELECT VALUE(e) FROM emp e;
SELECT eno, ename FROM emp;

どちらの問合せの場合も、Oracleデータベースはオブジェクト表empに対するユーザーのSELECT権限をチェックします。最初の問合せの場合、データを解析するには、ユーザーはemp_type型情報を取得する必要があります。問合せがemp_type型にアクセスすると、ユーザーのEXECUTE権限をチェックします。

2番目の問合せは、指定された型を必要としません。そのため、型権限をチェックしません。

また、USER3は次のような問合せを実行できます。

SELECT t.col1.attr2 from user2.tab2 t;
SELECT t.attr4.attr3.attr2 FROM tab3 t;

両方の問合せで、USER3は基礎となる型の明示的な権限を持っていないことに注意してください。ただし、型および表所有者はGRANTオプションを含む必要な権限を持っているため、この文は正常に実行されます。

次の要求についての権限をチェックし、ユーザーに各処理に対する権限がない場合はエラーを戻します。

- REF値を使用してオブジェクト・キャッシュ内に1つのオブジェクトを確保すると、そのオブジェクトを含むオブジェクト表に対するSELECT権限、およびそのオブジェクト型に対するEXECUTE権限をチェックします。

関連項目:
OCIプログラムをオブジェクトとともに効果的に使用するためのヒントおよび技法は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- 既存オブジェクトの変更、またはオブジェクト・キャッシュからのオブジェクトのフラッシュを行うと、接続先オブジェクト表に対するUPDATE権限をチェックします。新しいオブジェクトをフラッシュすると、接続先オブジェクト表に対するINSERT権限をチェックします。

- オブジェクトを削除すると、接続先の表に対するDELETE権限をチェックします。

- メソッドを起動すると、対応するオブジェクト型に対するEXECUTE権限をチェックします。

オブジェクト表に対する列レベルの権限は提供しません。

型依存性

この項では、2つの概要カテゴリで型依存性について説明します。

- 型が定義に対して相互に依存し、一方の型が他方の型の定義の一部である可能性がある状況。

- 型の作成または削除が表や型などの型が持つ依存性によって複雑になる状況。

この項の内容は次のとおりです。

- 不完全な型の作成

- 不完全な型の再定義

- 手動による型の再コンパイル

- 型および表の依存性がある場合のCREATE OR REPLACE TYPEの使用

- 代入可能な表および列の型依存性

- DROP TYPE FORCEオプション

- 型のシノニムの作成

- 型のシノニムの使用

不完全な型の作成

直接的または中間の型を介して定義に対して互いに依存する型を、相互依存といいます。たとえば、employeeの1つの属性を従業員が属する部門にし、departmentの1つの属性を部門を管理する従業員にするように、オブジェクト型employeeおよびdepartmentを定義できます。

矢印を使用して一連の相互依存型の関係を示す図を視覚化する場合、つながりがループを形成します。そのような循環依存を定義するには、サークルの最小限1つのセグメントにREFを使用する必要があります。

たとえば、例7-7に示す型を定義できます。

例7-7 依存オブジェクト型の作成

-- Requires Ex. 7-1 and password
CONNECT user1
-- Enter password
ALTER SESSION SET PLSQL_WARNINGS = 'enable:all';

CREATE TYPE department; // a placeholder
/

CREATE TYPE employee AS OBJECT (
name    VARCHAR2(30),
dept    REF department,
supv    REF employee );
/

CREATE TYPE emp_list AS TABLE OF employee;
/

CREATE TYPE department AS OBJECT (
name    VARCHAR2(30),
mgr     REF employee,
staff   emp_list );
/

これは、適切な相互依存型におけるSQL DDL文の適切な順序です。これをエラーなしでコンパイルします。

例7-7のコードはdepartment型を2回作成することに注意してください。最初の文は、employeeのREF属性が指すプレースホルダとして機能するdepartmentの不完全な宣言です。AS OBJECT句が省略され、属性またはメソッドがリストされていない点で、この宣言は不完全です。これらは、後述の型を完成させる完全な宣言で指定します。ここでは、departmentを不完全なオブジェクト型として作成しておきます。これにより、employeeがエラーなしでコンパイルできます。

不完全な型をプレースホルダとして作成しない場合、その型を参照する型はコンパイルされますが、コンパイル・エラーが発生します。たとえば、departmentが存在しない場合、それを不完全な型として作成し、employeeはコンパイル・エラーになります。この場合、次回なんらかの操作がこの型にアクセスする際に、employeeが再コンパイルされます。この型が依存するすべての型が作成され、その依存性が完全な場合、エラーなしでコンパイルされます。

不完全な型を使用することにより、まだ作成されていないサブタイプに対するREF属性を格納する型も作成できます。こうしたスーパータイプを作成するには、参照するサブタイプの不完全な型を最初に作成します。完全なサブタイプは、スーパータイプ作成後に作成します。

不完全な型の再定義

不完全な型が参照するすべての型を作成したら、不完全な型が不完全な状態を維持する必要がなくなるため、不完全な型の宣言を再定義してください。型を再定義すると、型が再コンパイルされ、システムが様々なロックを解放できるようになります。

不完全な型を再定義するには、例7-7の最後に示すとおり、型の属性およびメソッドを指定するCREATE TYPE文を実行します。

データベースによって作成される不完全な型も再定義する必要があります。前述の項で説明したように、不完全な型としてdepartmentを明示的に作成しなかった場合、データベースによって作成されました。この場合、引き続き再定義する必要があります。

不完全なオブジェクト型は、オブジェクト型として再定義する必要があります。オブジェクト型をコレクション型(ネストした表型または配列型)として再定義することはできません。その型を削除することはできます。

手動による型の再コンパイル

型の作成でコンパイル・エラーが発生し、その型に対してなんらかの操作(表の作成、行の挿入など)を実行しようとした場合、エラーが発生することがあります。この操作を行う前に、タイプを再コンパイルする必要があります。手動で型を再コンパイルする場合は、ALTER TYPE typename COMPILE文を実行します。型のコンパイルが正常に実行された後、操作を再試行してください。

型および表の依存性がある場合のCREATE OR REPLACE TYPEの使用

CREATE OR REPLACE TYPE文は、置換される型に表または型の依存性がある場合にエラーをスローします。これは、オブジェクト、VARRAYおよびネストした表の型に適用されます。また、継承または型の合成(一方の型をもう一方の型に埋め込む)に関連する型の依存性にも適用されます。継承または型の合成では、一方の型がもう一方の属性である場合があります。

CREATE OR REPLACE TYPE文でFORCEオプションを使用すると、型の依存性がある場合に型を置換できますが、表の依存性がある場合には置換できません。表の依存性はエラーの原因になります。

例7-8に、型の依存性が原因で失敗するCREATE OR REPLACE文を示します。

例7-8 CREATE OR REPLACEの型と表のエラー

SQL> CREATE type t1 AS OBJECT (a number) not final;
2  /
Type created.

SQL> CREATE TYPE t2 UNDER t1 (b varchar(10));
2  /
Type created.

SQL> CREATE OR REPLACE TYPE t1 AS OBJECT (c varchar(20));
2  /
CREATE OR REPLACE TYPE t1 AS OBJECT (c varchar(20));
*
ERROR at line 1:
ORA-02303: cannot drop or replace a type with type or table dependents

例7-9に示したコードでは、CREATE OR REPLACE FORCE文は、型の依存性を持つ型を置換した後で、親の型を使用した表の作成に成功します。ただし、最後のCREATE OR REPLACE FORCE文は、型が表の依存性を持つようになったため、失敗します(FORCEオプションを使用しても、表の依存性を持つ型は置換できません)。

例7-9 FORCEを指定したCREATE OR REPLACE

SQL> CREATE OR REPLACE TYPE t1 FORCE AS OBJECT (c varchar(20));
2  /
Type created.

SQL> CREATE TABLE tb1 (c1 t1);
Table created.

SQL> CREATE OR REPLACE TYPE t1 FORCE AS OBJECT (d number);
2  /
CREATE OR REPLACE TYPE t1 FORCE AS OBJECT (d number);
*
ERROR at line 1:
ORA-22866: cannot replace a type with table dependents

関連項目:
SQL文CREATE OR REPLACE TYPEの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

代入可能な表および列の型依存性

特定の型の代入可能な表または列は、その型のみでなく型のすべてのサブタイプも依存します。それは、型のサブタイプで追加されたそれぞれの属性について、非表示列が表に追加されることからもわかります。代入可能な表または列に、このサブタイプのデータが何も入っていない場合も、非表示列は追加されます。

関連項目:
代入性の詳細な説明は、「型階層内の型の代入」を参照してください。

例7-10で、型person_typのpersons表は、person_typのみでなく、person_typのサブタイプであるstudent_typおよびpart_time_student_typにも依存します。

依存型、表または列を持つサブタイプを削除しようとすると、DROP TYPE文はエラーを戻し、異常終了します。したがって、part_time_student_typは、persons表に依存しているので、削除しようとすると、エラーとなります。

依存表または依存列が存在しても、削除する型のデータが何も入っていない場合は、VALIDATEキーワードを使用して、型を削除できます。VALIDATEキーワードが使用されていると、指定された型のインスタンスが実際に格納されているかどうかを調べ、何も見つからなければ、型を削除します。型に固有の属性と関連付けられた非表示列も削除されます。

例7-10で、part_time_student_typに依存表(persons)があるため、最初のDROP TYPE文に失敗します。ただし、personsにpart_time_student_typのインスタンスが何も入っていなければ(および他の依存表または依存列のいずれも入っていなければ)、VALIDATEキーワードにより2番目のDROP TYPE文は正常に実行されます。

例7-10 VALIDATEを使用するおよび使用しないDROP TYPE

CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20))
NOT FINAL;
/
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30))
NOT FINAL;
/
CREATE TYPE part_time_student_typ UNDER student_typ (number_hours NUMBER);
/
CREATE TABLE persons OF person_typ;
-- Following generates an error due to presence of Persons table
DROP TYPE part_time_student_typ -- incorrect statement;
-- Following succeeds if there are no stored instances of part_time_student_typ
DROP TYPE part_time_student_typ VALIDATE;

注意:
サブタイプの削除中に、VALIDATEオプションを使用することをお薦めします。

DROP TYPE FORCEオプション

DROP TYPE文にはFORCEオプションもあり、このオプションを使用すると、型に依存型または依存表がある場合でも、型が削除されます。存在するすべての依存型または依存表に無効のマークが付けられ、型が削除されたときにアクセス不能になるので、FORCEオプションは慎重に使用します。この理由で無効になった表のデータに、再びアクセスすることはできません。こうした表に対して実行できる操作は、削除のみです。

型の変更方法の詳細は、「型進化」を参照してください。

オブジェクト型のシノニム

表、ビューおよびその他の様々なスキーマ・オブジェクトについてシノニムが作成できるように、オブジェクト型についてもシノニムを定義できます。

型のシノニムは、基礎となるスキーマ・オブジェクトを場所に依存せずに参照する手段となるため、他の種類のスキーマ・オブジェクトのシノニムと同じ利点があります。パブリック・タイプのシノニムを使用するアプリケーションは、データベースのスキーマを変更せずにデプロイでき、スキーマの名前で型の名前を修飾する必要はありません。

関連項目:
シノニムの詳細は、『Oracle Database管理者ガイド』を参照してください。

この項の内容は次のとおりです。

- 型のシノニムの作成

- 型のシノニムの使用

型のシノニムの作成

型のシノニムは、CREATE SYNONYM文で作成します。ユーザーには、CREATE SYNONYMおよび CREATE PUBLIC SYNONYM権限を付与しておく必要があります。

たとえば、これらの文はtyp1型を作成し、次にこの型のシノニムを作成します。

例7-11 user1のCREATE TYPE / SYNONYM

-- Example requires Ex.7-1 which created user1 and granted it the CREATE SYNONYM
-- and CREATE PUBLIC SYNONYM privileges
-- connect as user1 if not already connected.

CREATE TYPE typ1 AS OBJECT (x number);
/
CREATE SYNONYM syn1 FOR typ1;

シノニムは、コレクション型についても作成できます。次の例は、ネストした表型のシノニムを作成します。

CREATE TYPE typ2 AS TABLE OF NUMBER;
/
CREATE SYNONYM syn2 FOR typ2;

パブリック・シノニムは、PUBLICキーワードを使用して作成します。

CREATE TYPE shape AS OBJECT ( name VARCHAR2(10) );
/
CREATE PUBLIC SYNONYM pub_shape FOR shape;

REPLACEオプションを使用すると、シノニムが指す基礎となる型を別の型に変更できます。たとえば、次の文は、syn1が指す型をtyp2型に変更します。

CREATE OR REPLACE SYNONYM syn1 FOR typ2;

型のシノニムの使用

型のシノニムは、型を参照できるすべての場所で使用できます。たとえば、DDL文の中で型のシノニムを使用して、表列の型または型属性を指定できます。

例7-12では、シノニムsyn1を使用して、属性の型をtyp3型に指定します。

例7-12 CREATE文での型のシノニムの使用

-- Requires Ex 7-1 and connection as user1
-- drop syn1 and typ1 if created for Ex. 7-12
CREATE TYPE typ1 AS OBJECT (x number);
/
CREATE SYNONYM syn1 FOR typ1;

CREATE TYPE typ3 AS OBJECT ( a syn1 );
/

次の文で、型のシノニムsyn1は、syn1をシノニムとするオブジェクト型typ1のコンストラクタをコールします。この文は、typ1のオブジェクト・インスタンスを戻します。

SELECT syn1(0) FROM dual;

次の例は、syn2がネストした表型のシノニムです。シノニムは、CAST式の実際の型の名前と置き換わります。

SELECT CAST(MULTISET(SELECT eno FROM USER3.EMP) AS syn2) FROM dual;

このコードは、次の出力を戻します。

SQL> -- Type synonym used to call a constructor / nested table
SELECT syn1(0) FROM dual;
SELECT CAST(MULTISET(SELECT eno FROM USER3.EMP) AS syn2) FROM
dual;

SQL> SYN1(0)(X)
----------------------------------------------------------------
TYP1(0)

SQL>
CAST(MULTISET(SELECTENOFROMUSER3.EMP)ASSYN2)
----------------------------------------------------------------
TYP2()

型のシノニムは、次のような文で使用できます。

- DML文: SELECT、INSERT、UPDATE、DELETE、FLASHBACK TABLE、EXPLAIN PLANおよびLOCK TABLE

- DDL文: AUDIT、NOAUDIT、GRANT、REVOKEおよびCOMMENT

シノニムを使用するスキーマ・オブジェクトの記述

型のシノニムを使用して型または表が作成されると、DESCRIBEコマンドにより、これらのシノニムが表す型のかわりにシノニムが表示されます。同様に、型の名前を示すカタログ・ビュー(USER_TYPE_ATTRSなど)には、型のシノニムの名前が表示されます。

カタログ・ビューUSER_SYNONYMSを問い合せると、型のシノニムの基礎となる型を確認できます。

関連項目:
データ・ディクショナリ・カタログ・ビューの完全リストは、『Oracle Databaseリファレンス』の第2章を参照してください。

型のシノニムへの依存

型の宣言でシノニムを直接的または間接的に参照する型は、そのシノニムに依存します。したがって、例7-12の次の行に示す型typ3は、シノニムsyn1に依存する型です。

CREATE TYPE typ3 AS OBJECT ( a syn1 );
/

DDL文でシノニムを参照する他の種類のスキーマ・オブジェクトも、これらのシノニムに依存します。型のシノニムに依存するオブジェクトは、シノニムとシノニムの基礎になる型のどちらにも依存します。

シノニムの依存関係によって、シノニムが削除できるかどうか、または名前が変更できるかどうかが決まります。また、依存スキーマ・オブジェクトも、シノニムに対する操作の影響を受けます。次の項では、これらの様々な影響について説明します。

型のシノニムを置換する際の制限事項

シノニムに依存表または有効なユーザー定義型が存在しない場合にのみ、シノニムは置換できます。シノニムを置換することは、シノニムを削除してから、同じ名前で新しいシノニムを再作成することと同等です。

型のシノニムの削除

例7-13のように、シノニムはDROP SYNONYM文で削除します。

例7-13 型のシノニムの削除

CREATE SYNONYM syn4 FOR typ1;

DROP SYNONYM syn4;

型のシノニムに依存表または有効なオブジェクト型がある場合、型のシノニムを削除するには、FORCEオプションが必要です。FORCEオプションは、列の実際の型が削除された場合と同様に、直接的または間接的にシノニムに依存する列を、未使用とマークします。(たとえば、シノニムを使用して、列の宣言された型の属性の型を指定すると、列は間接的にそのシノニムに依存します。)

削除されたシノニムに依存するすべてのスキーマ・オブジェクトは無効になります。これらのスキーマ・オブジェクトは、削除されたシノニムと同じ名前のローカル・オブジェクトまたは新しいパブリック・シノニムを作成することで、再検証できます。

型のシノニムの基礎となるベース型の削除は、シノニムの削除と同じ結果を依存オブジェクトにもたらします。

型のシノニムの名前変更

型のシノニムの名前は、RENAME文で変更します。シノニムの名前を変更することは、シノニムを削除してから、新しい名前でシノニムを再作成することと同等です。型のシノニムに依存表または有効なオブジェクト型が存在する場合、型のシノニムの名前は変更できません。syn1には依存するオブジェクト型が存在するため、次の例は失敗します。

RENAME syn1 TO syn3 -- invalid statement;

型のパブリック・シノニムおよびローカル・スキーマ・オブジェクト

パブリック・シノニムが、新しいスキーマ・オブジェクトを保持するローカル・スキーマに依存表または有効なオブジェクト型を持っている場合、そのパブリック・シノニムと同じ名前のローカル・スキーマ・オブジェクトは作成できません。また、同じスキーマ内のプライベート・スキーマと同じ名前のローカル・スキーマ・オブジェクトも作成できません。

たとえば、次の例では、表shape_tabはパブリック・シノニムpub_shapeの依存表ですが、それは、この表に型の定義でこのシノニムを使用する列があるためです。したがって、依存表と同じスキーマにパブリック・シノニムpub_shapeと同じ名前の表を作成しようとすると、正常に実行されません。

-- Following uses public synonym pub_shape
CREATE TABLE shape_tab ( c1 pub_shape );
-- Following is not allowed
CREATE TABLE pub_shape ( c1 NUMBER ) -- invalid statement;

パフォーマンス・チューニング

オブジェクトのチューニング時には、次の点に対処する必要があります。

- オブジェクトおよびオブジェクト・ビューによる実行時のCPUおよびメモリー・リソースの消費状況

- 実行時のメモリーおよびCPUリソースの監視方法

- 多数のオブジェクトの管理方法

重要なパフォーマンス要因には、次のようなものがあります。

- 統計を収集するDBMS_STATSパッケージ

- SQLコマンドの実行をプロファイルするtkprof

- 問合せ計画を生成するEXPLAIN PLAN

関連項目:
アプリケーションのパフォーマンスの測定およびチューニングの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください

8 Oracleオブジェクトの高度なトピック

このマニュアルの前の章では、Oracleオブジェクトで作業を開始するために必要なトピックについて説明しています。この章では、オブジェクト・リレーショナル技法を大規模なアプリケーションまたは複雑なスキーマに適用する場合について説明します。

内容は次のとおりです。

- オブジェクトの記憶域

- 型IDまたは属性の索引作成

- 型進化

- システム定義およびユーザー定義コンストラクタ

- 一時型および汎用型

- ユーザー定義集計ファンクション

- ロケータでネストした表のパフォーマンスを向上させる方法

オブジェクトの記憶域

Oracleデータベースは、オブジェクト型の複合構造を、記憶域に対する単純な表構造に自動的にマップします。

関連する内容は次のとおりです。

- リーフ・レベル属性

- 列にまたがって分割される行オブジェクト

- 列オブジェクトを持つ表の非表示列

- 代入可能な列およびオブジェクト表の非表示列

- REFの記憶域

- ネストした表の内部レイアウト

- VARRAYの内部レイアウト

リーフ・レベル属性

オブジェクト型はツリー構造に似ており、ブランチが属性を表します。それ自体がオブジェクトである属性は、それ自体の属性でサブブランチを発生させます。

最終的に、各ブランチの終わりは、組込み型(NUMBER、VARCHAR2、REFなど)またはコレクション型(VARRAY、ネストした表など)の属性になります。元のオブジェクト型のこのようなリーフ・レベル属性は、それぞれ表の列に格納されます。

コレクション型ではないリーフ・レベル属性は、オブジェクト型のリーフ・レベル・スカラー属性と呼ばれます。

次の内容は、「オブジェクトを表に格納する方法」のオブジェクト表およびリレーショナル表の説明に関連しています。

列にまたがって分割される行オブジェクト

オブジェクト表では、すべてのリーフ・レベル・スカラー属性またはREF属性に対するデータが、個々の列に格納されます。

注意:
各VARRAYも、大きすぎないかぎり、列に格納されます。ネストした表型のリーフ・レベル属性は、オブジェクト表に対応付けられた個々の表に格納されます。これらの表は、オブジェクト表宣言の一部として宣言する必要があります。「VARRAYの内部レイアウト」および「ネストした表の内部レイアウト」を参照してください。

オブジェクト表にある行オブジェクトの属性を取り出したり、変更する場合、対応する操作が表の列で実行されます。行オブジェクト自体の値にアクセスすると、オブジェクト表の列を引数として使用し、その型のデフォルトのコンストラクタを起動して、オブジェクトのコピーを生成します。

システムによって生成されたオブジェクト識別子は、非表示列に格納されます。オブジェクト識別子を使用して、そのオブジェクトに対するREFを作成します。

列オブジェクトを持つ表の非表示列

表(リレーショナル表)がオブジェクト型の列とともに定義されている場合、オブジェクト型のリーフ・レベル属性に対する表に、非表示列が追加されます。オブジェクト型の各列には、その列オブジェクトのNULL情報(トップレベルのオブジェクトおよびネストしたオブジェクトのアトミックNULL)を格納するための非表示列があります。

代入可能な列およびオブジェクト表の非表示列

代入可能な列またはオブジェクト表には、その列のオブジェクト型の各属性に対してのみでなく、そのオブジェクト型のサブタイプに追加された各属性に対しても、非表示列があります。これらの列には、代入可能な列に挿入されたサブタイプのインスタンスに対する属性の値が格納されます。

型判別式の列およびNULLイメージ列以外に、次の列が例8-1で作成されるperson_typの代入可能な列に関連付けられます。

- person_typの各属性の非表示列: idno、nameおよびphone

- person_typのサブタイプの属性の非表示列

したがって、student_typに対する属性dept_idとmajorおよびpart_time_student_typに対する属性number_hoursがperson_typの代入可能な列に関連付けられる場合があります。

サブタイプを作成する場合、サブタイプの新しい属性の非表示列が、その新しいサブタイプの祖先クラスの代入可能な列を含む表に自動的に追加されます。追加された非表示列は、表にレトロフィットして、新しい型のデータを格納できるようになります。なんらかの理由で、非表示列を追加できない場合は、そのサブタイプの作成はロールバックされます。

VALIDATEオプションとともにDROP TYPEを使用してサブタイプを削除すると、データを含まないサブタイプの固有の属性に対する非表示列は、自動的に削除されます。これらの列にデータが含まれる場合、エラーが発生します。

例8-1では、この章の後続の例に必要な型を作成します。

例8-1 型の作成および表への挿入

-- drop any of these objects created for Ex.7-10
CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER )
NOT FINAL;
/
CREATE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
END;
/
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30))
NOT FINAL;
/
CREATE TYPE part_time_student_typ UNDER student_typ (
number_hours NUMBER);
/
CREATE TYPE employee_typ UNDER person_typ (
emp_id NUMBER,
mgr VARCHAR2(30));
/
CREATE TABLE person_obj_table OF person_typ;  // an object table
INSERT INTO person_obj_table
VALUES (person_typ(12, 'Bob Jones', '650-555-0130'));
INSERT INTO person_obj_table
VALUES (student_typ(51, 'Joe Lane', '1-650-555-0140', 12, 'HISTORY'));
INSERT INTO person_obj_table
VALUES (part_time_student_typ(52, 'Kim Patel', '1-650-555-0135', 14,
'PHYSICS', 20));

代入可能な列は、非表示の型判別式の列に関連付けられます。非表示列には、型IDと呼ばれる識別子があり、この識別子によって、代入可能な列中の各オブジェクトのうち、最も具体的な型が識別されます。通常、型ID(RAW)は1バイトですが、大きな階層の場合は最大4バイトまでとなります。

指定されたオブジェクト・インスタンスの型IDは、ファンクションSYS_TYPEIDを使用して特定できます。

例8-2では、例8-1で作成される代入可能なオブジェクト表に格納されるオブジェクト・インスタンスの型IDを取り出します。

例8-2 表に格納されるオブジェクトの型IDの問合せ

-- Requires Ex. 8-1
SELECT name, SYS_TYPEID(VALUE(p)) typeid
FROM person_obj_table p;

NAME TYPEID
------------------------------ ---------------------------
Bob Jones 01
Joe Lane 02
Kim Patel 03

カタログ・ビューのUSER_TYPES、DBA_TYPESおよびALL_TYPESには、各型に対する型ID値を与えるTYPEID列(非表示ではない)があります。この列に対して結合を実行して、型判別式の列にある型IDに対応する型名を取得できます。

関連項目:
SYS_TYPEID、型IDおよび型判別式の列の詳細は、「SYS_TYPEID」を参照してください。

REFの記憶域

データベースが行オブジェクトに対してREFを作成する場合、その作成されるREFは、オブジェクト識別子(OID)、オブジェクト表のいくつかのメタデータ、およびROWID (オプション)で構成されます。

REF型の列にあるREFのサイズは、次のその列に対応付けられた記憶域要件に依存します。

- 列がREF WITH ROWIDとして宣言されている場合、ROWIDはREF列に格納されます。ROWIDのヒントは、制約付きREF列にあるオブジェクト参照では無視されます。

- 列がSCOPE句を使用してREFとして宣言されている場合、オブジェクト表のメタデータおよびROWIDの省略によって、その列は少なくなります。有効範囲付きREFの長さは、16バイトです。

オブジェクト識別子が主キー・ベースの場合、主キーを導出する列の数に基づいて、主キーの値を格納するための1つ以上の内部列が作成されます。

注意:
オブジェクト識別子が主キーから導出される行オブジェクトをREF列が参照する場合、このREF列を、主キー・ベースREFまたはpkREFといいます。pkREFを含む列は、有効範囲付きであるかまたは参照制約が指定されている必要があります。

ネストした表の内部レイアウト

ネストした表の行は、別の記憶表に格納されます。ネストした表には、列ごとに1つの記憶表が対応付けられています。記憶表は、その列にあるすべてのネストした表に対するすべての要素を保持しています。記憶表には、システム生成の値を持つ非表示のNESTED_TABLE_ID列があり、この値によって、Oracle Databaseでは、ネストした表の要素が適切な行にマップされます。

記憶表を索引構成表にすることによって、コレクション全体を取り出す問合せを高速化できます。ORGANIZATION INDEX句をSTORE AS句の中に挿入します。

「ネストした表の記憶域」を参照してください。

ネストした表型は、オブジェクトまたはスカラーを含むことができます。

- 要素がオブジェクトである場合、記憶表はオブジェクト表のようになります。つまり、そのオブジェクト型のトップレベルの属性が記憶表の列となります。ただし、ネストした表の行にはオブジェクト識別子列がないため、ネストした表のオブジェクトに対してREFは作成できません。

- 要素がスカラーである場合、記憶表には、スカラー値を含むCOLUMN_VALUEという単一の列が含まれます。

VARRAYの内部レイアウト

VARRAYのすべての要素は、単一の列に格納されます。配列のサイズに基づいて、インラインまたはBLOBに格納されます。詳細は、「VARRAYの記憶域上の考慮点」を参照してください。

型IDまたは属性の索引作成

この項では、型IDおよび属性での索引の使用方法を説明します。

この項の内容は次のとおりです。

- 型判別式の列の索引付け

- 代入可能なサブタイプの索引付け

型判別式の列の索引付け

SYS_TYPEIDファンクションを使用して、代入可能な列の非表示の型判別式の列に索引を作成できます。型判別式の列には、型IDがあり、この識別子によって、代入可能な列中の各オブジェクト・インスタンスのうち、最も具体的な型が識別されます。この情報は、IS OF述語を使用して型に基づいてフィルタにかける問合せの評価に使用されるものですが、SYS_TYPEIDファンクションを使用して独自の目的で型IDにアクセスすることも可能です。

一般に、型判別式の列には、わずかな数の型IDのみが格納されています。関連のある型階層に含まれている型の数を超えることはありません。この列はカーディナリティが低いので、ビットマップ索引の作成に適しています。

たとえば、次の文では、表contactsの代入可能なcontact列の基礎となる型判別式の列のビットマップ索引を作成します。ファンクションSYS_TYPEIDは、型判別式の列を参照します。

例8-3 代入可能な列のビットマップ索引の作成

-- Requires Ex. 8-1
CREATE TABLE contacts (
contact         person_typ,
contact_date    DATE );
INSERT INTO contacts VALUES (
person_typ (65,'Vrinda Mills', '1-650-555-0125'),'24 Jun 2003' );
INSERT INTO contacts VALUES (
person_typ (12, 'Bob Jones', '650-555-0130'),'24 Jun 2003' );
INSERT INTO contacts VALUES (
student_typ(51, 'Joe Lane', '1-650-555-0140', 12, 'HISTORY'),'24 Jun 2003' );
INSERT INTO contacts VALUES ( part_time_student_typ(52, 'Kim Patel', '1-650-555-0135', 14, 'PHYSICS', 20),'24 Jun 2003' );
CREATE BITMAP INDEX typeid_idx ON contacts (SYS_TYPEID(contact));

代入可能なサブタイプの索引付け

代入可能な列内に格納できる任意の型の属性に対して索引を作成できます。サブタイプの属性は、TREATファンクションを使用して求めるサブタイプ(およびそのサブタイプ)以外の型をフィルタにかけて排除することによってCREATE INDEX文で参照できます。その後、ドット表記によって、希望の属性を指定します。

たとえば、次の文では、contacts表にある、すべての学生のmajor属性に対する索引が作成されます。contact列の宣言された型はperson_typで、student_typがそのサブタイプであるため、この列にはperson_typ、student_typのインスタンスおよびいずれかのサブタイプを格納できます。

例8-4 すべての学生の属性に対する索引の作成

-- Requires Ex.8-1- and 8-3
CREATE INDEX major1_idx ON contacts
(TREAT(contact AS student_typ).major);

student_typは、最初にmajor属性を定義しました。person_typスーパータイプにはこの型はありません。したがって、major属性に対する非表示列のすべての値は、個人の型student_typまたはparttimestudent_typ (student_typサブタイプ)に対する値です。つまり、非表示列の値は、学生のサブタイプも含めてすべての学生のmajorの値のTREAT式によって戻される値と同一であることを意味しています。つまり、非表示列も、TREAT式もともに、学生については専攻を、学生以外についてはNULLをリストします。このことを利用して、非表示列に対する索引major1_idxが、通常のBツリー索引として作成されます。

非表示列の値が、前述のように、TREAT式によって戻される値と同一になるのは、TREATファンクションのターゲットとして指定された型(student_typ)が最初にそのmajor属性を定義した型である場合にかぎります。TREATファンクションのターゲットが、次の例のように、単にその属性を継承するサブタイプである場合は、TREAT式は、サブタイプ(定時制の学生)に対してはNULL以外のmajor値を戻しますが、スーパータイプ(その他の学生)に対しては非NULLは戻しません。

CREATE INDEX major2_idx ON contacts
(TREAT(contact AS part_time_student_typ).major);

この場合、非表示列にmajorの値として格納されている値は、TREAT式の結果とは異なっている場合があります。したがって、通常のBツリー索引を基礎となる列に対して作成することはできません。したがって、データベースでは、TREAT式は他のすべてのファンクション・ベースの式と同様に処理され、索引を、結果に対するファンクション索引として作成する試みが行われます。

次の例では、前述の例と同様に、定時制の学生のmajor属性に対してファンクション索引を作成しますが、この例では、majorの非表示列は、代入可能なオブジェクト表person_obj_tableに対応付けられています。

CREATE INDEX major3_idx ON person_obj_table p
(TREAT(VALUE(p) AS part_time_student_typ).major);

型進化

型進化は、オブジェクト型を変更するプロセスです。オブジェクト型は、次の方法で変更できます。

- 属性の追加および削除

- メソッドの追加および削除

- 長さ、精度または位取りを引き上げるための数値属性の修正

- 文字長を長くするための可変長文字属性の修正

- 型のFINALおよびINSTANTIABLEプロパティの変更

- VARRAYの制限およびサイズの変更

- コレクション要素の長さ、精度およびスケールの変更

型を変更すると、その型を参照する項目にも影響します。たとえば、新しい属性を型に追加する場合、その新しい属性を追加できるように、その型の列にあるデータを提示する必要があります。

この項の内容は次のとおりです。

- 型進化および依存スキーマ・オブジェクト

- データを更新するオプション

- 型への構造的な変更の影響

- ネストした表属性の追加による型の変更

- 変更された型の妥当性チェック

- 型の変更の妥当性チェックに失敗した場合

- 型進化に使用するALTER TYPE文

- 型進化に使用するALTER TABLE文

型進化および依存スキーマ・オブジェクト

型の依存スキーマ・オブジェクトは、型を直接的または間接的に参照し、その型に加えられた変更に影響されるオブジェクトです。

型は、次の依存スキーマ・オブジェクトを持つことができます。表、型またはサブタイプ、プロシージャ、ファンクション、パッケージ、トリガーなどのプログラム・ユニット(PL/SQLブロック)、索引タイプ、ビュー(オブジェクト・ビューを含む)、ファンクション索引、演算子。

依存スキーマ・オブジェクトが型の変更によってどのような影響を受けるかは、オブジェクトによって、また、変更の性質によって異なります。

- 依存プログラム・ユニット、ビュー、演算子および索引タイプは、型が変更されると、無効としてマークされます。これらの無効となったスキーマ・オブジェクトのいずれかが次回参照されると、新しい型の定義を使用して再検証されます。オブジェクトの再コンパイルが成功すると、そのオブジェクトは有効となり、再度使用できるようになります。

- 型の変更によっては、依存ファンクション索引が削除または無効化され、再構築が必要です。

- 依存表には、属性の型に応じて型に加えられた各属性に対して表に1つ以上の内部列が追加されます。新しい属性が追加される際は、NULL値が設定されます。削除された各属性に対応付けられている列は削除されます。変更された各属性に対応付けられた長さ、精度またはスケールも、変更内容に対応して変更されます。

これらの変更は、主に表のメタデータの更新を含み、迅速に実行できます。さらに、このような表データは、「データを更新するオプション」で説明するように、型の新しいバージョンの形式に合せた更新も必要です。

データを更新するオプション

更新は、データの量によっては時間がかかる場合があるため、ALTER TYPEコマンドにオプションが用意されています。このオプションによって、すべての依存表データを即時変換するか、元の形式のままにしておいて、更新のたびに少しずつ変換するかを選択できます。

ALTER TYPEのCASCADEオプションは、型の変更を依存型および依存表に伝播します。「型進化に使用するALTER TYPE文」を参照してください。CASCADE自体に、伝播の一環として表データを新しい型形式に変換するかどうかを選択できる次のオプションがあります。

- INCLUDING TABLE DATA: データを変換します(デフォルト)

- NOT INCLUDING TABLE DATA : データを変換しません

デフォルトでは、CASCADEオプションはデータを変換します。いずれの場合も、表データは常に最新バージョンの型の形式で戻されます。表データが以前の型バージョンの形式で保存されている場合は、データが実際に保存されている形式はデータが再書込みされないかぎり変更されないにしても、そのデータは、戻される前に最新バージョンの形式に変換されます。

最新の型の定義は、システム・ビューUSER_SOURCEから取り出せます。USER_TYPE_VERSIONSビューで、ある型のすべてのバージョンの定義を参照できます。

関連項目:

型の定義および型本体のコンパイルの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

型への構造的な変更の影響

型に対する構造的な変更が依存データに影響し、データの変換を必要とします。これは、ある型のメソッドの定義や動作(実装)に限定された変更には適用されません。

型に対する次の変更は構造的変更です。

- 属性の追加または削除

- 属性の長さ、精度、スケールの変更

- FINALからNOT FINALに(またはその逆に)型のファイナリティを変更します

このような変更の結果、変更された型およびそのすべての依存型のバージョンが新しいバージョンになり、新しいバージョンへの変更のプロセスの一環として、依存表の内部列が追加、削除または変更されます。

これらのいずれかの変更を、依存型または依存表を持つ型に対して実行すると、変更を伝播した影響は、メタデータのみでなく、データ記憶域の構成にも影響し、データの変換を必要とします。

データの変換以外にも、変更すべき項目がある場合があります。たとえば、新しい属性が型に追加されて、その型が、その型のコンストラクタをコールする場合、型本体の各コンストラクタは、新しい属性に対する値を指定するように修正する必要があります。同様に、新しいメソッドが追加される場合は、型本体を置換して、新しいメソッドの実装を追加する必要があります。型本体は、CREATE OR REPLACE TYPE BODY文を使用して変更できます。

属性の追加および削除による型の変更

例8-5に、ある属性を追加し、別の属性を削除することによってperson_typに単純な変更を加える方法を示します。CASCADEキーワードは、型の変更を依存型および依存表に伝播しますが、NOT INCLUDING TABLE DATA句によって関連するデータの変換が阻止されています。

例8-5 属性の追加および削除によるオブジェクト型の変更

-- Drop person_typ and person_obj_table if they exist
CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20));
/
CREATE TABLE person_obj_table OF person_typ;

INSERT INTO person_obj_table
VALUES (person_typ(12, 'Bob Jones', '650-555-0130'));

SELECT value(p) FROM person_obj_table p;

VALUE(P)(IDNO, NAME, PHONE)
--------------------------------------------
PERSON_TYP(12, 'Bob Jones', '650-555-0130')

次のように電子メール属性を追加し、電話属性を削除できます。

ALTER TYPE person_typ
ADD ATTRIBUTE (email VARCHAR2(80)),
DROP ATTRIBUTE phone CASCADE NOT INCLUDING TABLE DATA;

次に、型の変更に対応するために切断して再接続します。

connect oe/oe;
connect hr/hr;
ALTER SESSION SET PLSQL_WARNINGS = 'enable:all';
-- The data of table person_obj_table has not been converted yet, but
-- when the data is retrieved, Oracle returns the data based on
-- the latest type version. The new attribute is initialized to NULL.
SELECT value(p) FROM person_obj_table p;

VALUE(P)(IDNO, NAME, EMAIL)
---------------------------------
PERSON_TYP(12, 'Bob Jones', NULL)

SELECT文では、列データが最新の型バージョンに変換されている可能性があるとしても、変換されたデータが列に再度書き込まれることはありません。ある表の特定のユーザー定義型の列が頻繁に取り出される場合、データ変換が重複して行われないようにするため、そのデータを最新の型バージョンに変換することを検討してください。変換は、列にオブジェクトやネストした表列より変換に必要な時間が通常長くなるVARRAY属性が含まれている場合、特に大きな効果があります。

前のコードと関連していない次のコード・スニペットに示すように、UPDATE文を発行して列をそれ自体に設定し、データの列を変換できます。

UPDATE dept_tab SET emp_array_col = emp_array_col;

ある表内のすべての列を、UPGRADE INCLUDING DATAとともにALTER TABLEを使用して変換できます。次に例を示します。

ALTER TYPE person_typ ADD ATTRIBUTE (photo BLOB)
CASCADE NOT INCLUDING TABLE DATA;
ALTER TABLE person_obj_table UPGRADE INCLUDING DATA;

ALTER TABLE行は、リストされた表のみを変換します。CASCADEオプションは、他の表または依存オブジェクトが変換されないようにします。

ネストした表属性の追加による型の変更

この項では、ネストした表に含まれているオブジェクト型にネストした表属性を追加する型に複雑な変更を加える手順を説明します。

例8-6は、例8-7で変更される初期スキーマを示します。

例8-6 初期スキーマ

-- Drop existing person_typ, department_type, people_typ objects or tables
CREATE TYPE person_typ AS OBJECT (
idno           NUMBER,
name           VARCHAR2(30),
phone          VARCHAR2(20));
/
-- creating a nested table type
CREATE TYPE people_typ AS TABLE OF person_typ;/
CREATE TYPE department_typ AS OBJECT (
manager    person_typ,
employee   people_typ);  // a nested table/
CREATE TABLE department OF department_typ
NESTED TABLE employee STORE AS employee_store_nt;

例8-7は、新しいオブジェクトtasks_typおよびそれを保持するネストした表の型tasks_nttabの作成から開始されます。

属性としてネストした表tasksをネストした表people_typにすでに含まれているオブジェクト型person_typに追加するには、例8-7および他のプログラムの両方で次の手順が必要です。

1. ALTER TYPE..INVALIDATE文を発行して、型person_typを変更します。この文では、時間を節約するために型および表のチェックをすべて迂回して、依存オブジェクトを無効にします。表のデータには、有効化されるまでアクセスできません。
ALTER TYPE文には、ネストした表tasksを追加するADD ATTRIBUTEが含まれます。

UPGRADE.. STORE AS句は、影響を受けるネストした表をアップグレードし、新規の記憶表の名前を指定します。

例8-7 ネストした表属性の追加によるオブジェクト型の変更

-- Requires Ex. 8-6
CREATE TYPE tasks_typ AS OBJECT (
priority       VARCHAR2(2),
description    VARCHAR2(30));
/

CREATE TYPE tasks_nttab AS TABLE OF tasks_typ;
/

ALTER TYPE person_typ ADD ATTRIBUTE tasks tasks_nttab
INVALIDATE;

-- Propagate the change to employee_store_nt
-- Specify a storage name for the new nested table
ALTER TABLE employee_store_nt
UPGRADE NESTED TABLE tasks STORE AS tasks_nt;

2. 必要な場合は、person_typに対するCREATE OR REPLACE TYPE BODYを使用して、対応する型本体を更新して、新しい型定義に更新します。

3. 依存表を最新の型バージョンにアップグレードし、表データを変換します。これにより、表が検証され、データ・アクセスが再度許可されます。

ALTER TABLE department UPGRADE INCLUDING DATA;

4. 必要に応じて、PL/SQL依存プログラム・ユニットを変更して、型に加えられた変更に対応します。

5. アプリケーションがC言語で書かれているか、Javaで書かれているかによって、OTTまたはJPublisherを使用して、新しいヘッダー・ファイルを生成します。
スーパータイプに新しい属性を追加すると、サブタイプの属性が新しい属性を継承するために、そのすべてのサブタイプの属性数が増大する可能性があります。継承された属性は、常に、宣言された(ローカルに定義された)属性に先行するので、新しい属性をスーパータイプに追加すると、各サブタイプのすべての宣言された属性の順序が1つずつ再帰的に増加されます。変更された型のマッピングを更新して、新しい属性を追加する必要があります。Oracle Type Translator (OTT)およびJPublisherがこれを行います。別のツールを使用する場合は、型のヘッダーが、サーバーでの型の定義と適切に同期されることを確認する必要があります。この同期が確実に行われない場合は、結果として予期しない動作が発生する可能性があります。

6. 必要に応じてアプリケーション・コードを修正し、アプリケーションを再作成します。

変更された型の妥当性チェック

ALTER TYPE文の実行の際に、最初に、要求された型の変更について、構文上およびセマンティクス上の妥当性がチェックされます。CREATE TYPE文についても同様の妥当性チェックおよび追加の妥当性チェックが実行されます。ターゲットの型の新しい仕様またはその依存型のいずれかについて型の妥当性が確認されない場合は、ALTER TYPE文は異常終了します。この場合は、新しい型バージョンは作成されず、すべての依存オブジェクトが変更されないままになります。

依存表が存在する場合は、さらにチェックが行われて、表および索引に関連する制約が遵守されているかが確認されます。たとえば、削除の対象となっている属性が、パーティション化キーで使用されていないかが確認されます。ここでも、ALTER TYPE文について、表に関連する制約のチェックが失敗すると、型の変更は異常終了し、その型の新しいバージョンは作成されません。

単一のALTER TYPE文で複数の属性を追加する場合、指定された順序で実行されます。1つのALTER TYPE文で複数の型の変更を指定することはできますが、属性名およびメソッド・シグネチャは1回のみの指定となります。たとえば、単一の文で同じ属性の追加と変更を行うことはできません。

次の項では、次の型の変更に関するその他の注意事項について説明します。

- 属性の削除

- 属性の型の長さ、精度、スケールの変更

- メソッドの削除

- INSTANTIABLEプロパティの変更

属性の削除

- ルート型に由来するすべての属性を削除することはできません。かわりに、型を削除する必要があります。サブタイプのすべての属性はスーパータイプから継承されるため、サブタイプからすべての属性を削除しても、その属性のカウントは0 (ゼロ)にはなりません。サブタイプでローカルに宣言された属性を削除することは許可されます。

- ターゲットの型でローカルに宣言された型のみを削除できます。継承された属性を、サブタイプから削除することはできません。属性がローカルに宣言された場所でその型からその属性を削除してください。

- 表パーティションの一部である属性または表のサブパーティション・キーの削除はできません。

- オブジェクト表またはIOTの主キーOIDの属性の削除はできません。

- 属性が削除されると、削除された属性に対応する列は削除されます。

- 属性を削除すると、索引、統計、制約、および属性を参照する参照整合性制約が削除されます。

属性の型の長さ、精度、スケールの変更

- 依存表のファンクション索引、クラスタ・キーまたはドメイン索引で参照される属性の長さは拡張できません。

- 属性の長さ、精度、スケールを縮小できません。

メソッドの削除

- メソッドは、そのメソッドの定義(または再定義)が行われた型からのみ削除できます。継承されたメソッドをサブタイプから削除することはできません。また、再定義したメソッドをスーパータイプから削除することもできません。

- メソッドが再定義されていない場合、CASCADEオプションを使用してそのメソッドを削除すると、ターゲットの型に由来するメソッドおよびすべてのサブタイプが削除されます。一方、メソッドがサブタイプで再定義されている場合は、CASCADEは実行されないで、ロールバックされます。CASCADEが実行されるためには、メソッドを定義しているサブタイプから再定義されたメソッドを削除して、その後、スーパータイプからメソッドを削除します。
USER_DEPENDENCIES表に、型も含めて、与えられた型に依存するすべてのスキーマ・オブジェクトがあります。また、DBMS_UTILITY.GET_DEPENDENCYユーティリティを実行して、型の依存関係を検索できます。

- INVALIDATEオプションを使用して、再定義されたメソッドを削除できますが、サブタイプの再定義されたバージョンは、依然として手動で削除する必要があります。サブタイプは、再定義されたバージョンを削除するように明示的に変更されないかぎり、無効な状態のままです。それまでは、妥当性チェックのためにサブタイプを再コンパイルしようとすると、「メソッドは上書きしません。」というエラーが発生します。
CASCADEとは異なり、INVALIDATEは、型および表のすべてのチェックを迂回して、その型に依存するすべてのスキーマ・オブジェクトを無効とします。それらのオブジェクトは、次回のアクセス時に再検証されます。このオプションは、CASCADEを使用するより高速に処理されますが、依存型および依存表の再検証時に問題が発生しないことが確認されている必要があります。表が無効な場合は、表データにはアクセスできません。表の妥当性が検証できない場合は、そのデータはアクセス不可のままとなります。

「型の変更の妥当性チェックに失敗した場合」を参照してください。

INSTANTIABLEプロパティの変更

- その型に表依存オブジェクトがない場合にかぎり、オブジェクト型をINSTANTIABLEからNOT INSTANTIABLEへ変更できます。

- オブジェクト型のNOT INSTANTIABLEからINSTANTIABLEへの変更は任意の時点で実行できます。このように変更した場合、表には影響しません。

FINALプロパティの変更

- ターゲットの型にサブタイプがない場合にかぎり、オブジェクト型をNOT FINALからFINALへ変更できます。

- オブジェクト型をFINALからNOT FINAL、またはその逆に変更する場合は、CASCADEを使用して依存列内および依存表内のデータを即時変換する必要があります。CASCADEオプションNOT INCLUDING TABLE DATAを使用して、データを遅延させることはできません。

- NOT FINALからFINALへは、CASCADE INCLUDING TABLE DATAを使用する必要があります。

- FINALからNOT FINALへは、CASCADE INCLUDING TABLE DATAまたはCASCADE CONVERT TO SUBSTITUTABLEのいずれかを使用できます。
FINALからNOT FINALに型を変更する場合、変更した型の新規サブタイプを既存の列および表に挿入するかどうかに基づいて、CASCADEオプションを選択します。

デフォルトでは、型をFINALからNOT FINALに変更することで、代入可能な新しい表およびその型の列を作成できますが、その型の既存の列(またはオブジェクト表)が自動的に代入可能になることはありません。実際、その逆の動作が行われます。その型の既存の列および表はNOT SUBSTITUTABLE AT ALL LEVELSとマークされます。これらの列の埋込み属性が代入可能な場合は、エラーが生成されます。変更された型の新しいサブタイプは、これらの既存の列および表には挿入できません。

既存の型の列および表を代入可能にするようオブジェクト型をNOT FINALに変更する場合(NOT SUBSTITUTABLEとマークされていないことを前提)は、CASCADEオプションCONVERT TO SUBSTITUTABLEを使用します。

例8-8は、オプションCONVERT TO SUBSTITUTABLEを含むCASCADEの使用を示します。

例8-8 FINALからNOT FINALへの型の変換

CREATE TYPE shape AS OBJECT (
name VARCHAR2(30),
area NUMBER)
FINAL;/
ALTER TYPE shape NOT FINAL CASCADE CONVERT TO SUBSTITUTABLE;

このCASCADEオプションにより既存の列がSUBSTITUTABLE AT ALL LEVELSとマークされ、列に格納されたインスタンスの型ID用に新しい非表示列が追加されます。その後、変更された型のサブタイプ・インスタンスを列に格納できます。

型の変更の妥当性チェックに失敗した場合

ALTER TYPE文のINVALIDATEオプションを使用して、依存オブジェクトに加えた型の変更を伝播することなく型の変更ができます。この場合、依存型および依存表の妥当性チェックは行われません。つまり、型の変更によるすべての影響が妥当であることを確認しません。かわりに、すべての依存スキーマ・オブジェクトに無効のマークが付けられます。これらのオブジェクト(型や表など)は、次回の参照時に再検証されます。型の再検証ができない場合、その型は無効のままとなり、そのような型を参照する表も、問題が修正されるまではアクセス不可となります。

表が妥当性チェックに失敗するのは、次のような理由です。型に新しい属性を追加してその表内の一部の列が、最大1000を超えた場合またはある表のパーティション化キーまたはクラスタ化キーとして使用されている属性が型から削除された場合。

型の再検証は、ALTER TYPE COMPILE文を発行すると強制的に実行できます。無効な表の再検証を強制的に実行するには、ユーザーは、ALTER TABLE UPGRADE文を発行して、データを最新の型バージョンに変更するかどうかを指定できます。

注意:
表の参照時にトリガーされた表の妥当性チェックにおいて、表データは常に最新の型バージョンになるよう更新されます。データの変換を延期するオプションはありません。

表を最新の型バージョンに変換できない場合、その表に対するINSERT文、UPDATE文およびDELETE文は使用できず、その表データにはアクセスできなくなります。その表に対して次のDDLは実行できますが、無効な表を参照する他のすべての文は、その表の妥当性が検証されるまで使用できません。

- DROP TABLE

- TRUNCATE TABLE

ある表の%ROWTYPEまたはある列の%TYPE、あるいはある表にある属性を使用して定義された変数を含むすべてのPL/SQLプログラムは、最新の型バージョンに基づいてコンパイルされます。その表の再検証が失敗すると、その表を参照する任意のプログラム・ユニットのコンパイルも失敗します。

型進化に使用するALTER TYPE文

表8-1に、型の属性またはメソッド定義を変更するために使用するALTER TYPEおよびALTER TYPE...CASCADE文の一部の重要なオプションを示します。

表8-1 型進化に使用するALTER TYPEオプション

オプション

説明

INVALIDATE

すべての依存オブジェクトを無効とします。このオプションを使用して、型および表のすべてのチェックを迂回し、時間を節約します。

このオプションは、依存型および依存表の再検証において問題が発生しないことが確実な場合に使用してください。表の妥当性が検証されるまでは表データにはアクセスできません。表の妥当性チェックができない場合は、そのデータはアクセス不可のままになります。

CASCADE

型の変更を依存型および依存表に伝播します。この文は、FORCEオプションが指定されていないかぎり、依存型または依存表にエラーが検出されると異常終了します。

他のオプションなしにCASCADEが指定されていると、CASCADEに対してINCLUDING TABLE DATAオプションが暗黙的に指定され、すべての表データが最新の型バージョンに変換されます。

INCLUDING TABLE DATA (CASCADEのオプション)

すべてのユーザー定義列に格納されているデータを、列の型の最新バージョンに変換します。

列の型に追加された新しい属性ごとに、新しい属性がデータに追加され、NULLに初期化されます。参照される型から削除された属性ごとに、対応する属性データが表から削除されます。表のデータが格納されているすべての表領域は、読取り/書込みモードにする必要があります。そうしないと、この文の処理は失敗します。

NOT INCLUDING TABLE DATA (CASCADEのオプション)

列データをそのまま維持し、型バージョンを変更しません。属性が表が参照する型から削除されても、削除された属性の対応する列は表から削除されません。ただし、その列のメタデータが未使用とマークされるのみです。削除された属性が列外(たとえば、VARRAY属性、LOB属性、またはネストした表属性)に格納されている場合は、その列外のデータは削除されません。(使用されない列は、後で、ALTER TABLE DROP UNUSED COLUMNS文を使用して削除できます。)

このオプションは、数多くの大きな表があり、1つのトランザクションでそのすべてを変換すると、ロールバック・セグメントが不足する可能性がある場合に使用します。このオプションを使用して、後で、各依存表のデータを、別個のトランザクションで変換できます(ALTER TABLE UPGRADE INCLUDING DATA文を使用します)。

このオプションを指定すると、表のデータは、以前の型バージョンの形式のまま維持されるので、表の更新が高速化されます。ただし、この表からデータを選択するには、その列に格納されているイメージを最新の型バージョンに変換する必要があります。この操作は、後続のSELECT文が実行される際のパフォーマンスに影響を及ぼす可能性があります。

このオプションは、表のメタデータの更新のみを必要とするため、文を正常に実行するためにすべての表領域の読取り/書込みモードでのオンライン化が必要なわけではありません。

FORCE (CASCADEのオプション)

システムに、依存表および索引からのエラーを無視させます。エラーについては、後で問合せができるように、指定された例外表にログが作成されます。一部の表でエラーが発生した場合、依存表にアクセスできなくなる可能性があるので、このオプションは慎重に使用してください。

CONVERT TO SUBSTITUTABLE (CASCADEのオプション)

型をFINALからNOT FINALに変更する場合に使用するオプションで、すべてのユーザー定義列に格納されているデータを、最新バージョンの列の型に変換し、型の新しく作成されたサブタイプがSUBSTITUTABLE AT ALL LEVELS型の既存の列およびオブジェクト表に格納できるように、これらの列および表をマークします。

このオプションを指定せずに、型をNOT FINALに変更した場合、その型の既存の列および表はNOT SUBSTITUTABLE AT ALL LEVELSとマークされ、その型の新しいサブタイプをこれらの列および表に格納できません。型が変更された後に作成される列および表にのみこれらのサブタイプを格納できます。

関連項目:
ALTER TYPEオプションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

型進化に使用するALTER TABLE文

ALTER TABLEを使用して、参照される型の最新バージョンに表データを変換できます。例は、「ネストした表属性の追加による型の変更」を参照してください。INCLUDING DATAオプションの詳細は、表8-1を参照してください。

関連項目:
ALTER TABLEオプションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

システム定義およびユーザー定義コンストラクタ

この項では、属性値コンストラクタとも呼ばれるシステム定義コンストラクタおよびユーザー定義コンストラクタを使用する様々な側面を説明します。

この項の内容は次のとおりです。

- 属性値コンストラクタ

- コンストラクタと型進化

- ユーザー定義コンストラクタの利点

- ユーザー定義コンストラクタの定義および実装

- コンストラクタのオーバーロードおよび隠蔽

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

- SQLJオブジェクト型のコンストラクタ

属性値コンストラクタ

属性値コンストラクタとも呼ばれるシステム定義コンストラクタの場合、型の各属性値をコンストラクタに渡す必要があります。すると、例8-9に示すように、コンストラクタにより、新しいオブジェクト・インスタンスの属性にこれらの値が設定されます。

例8-9 コンストラクタによる属性値の設定

CREATE TYPE shape AS OBJECT (
name VARCHAR2(30),
area NUMBER);
/
CREATE TABLE building_blocks of shape;

-- attribute-value constructor: Sets instance attributes to the specified values
INSERT INTO building_blocks
VALUES (
NEW shape('my_shape', 4));

NEWは、コンストラクタへのコールの前にオプションで追加するキーワードです。このキーワードを追加することをお薦めします。

コンストラクタと型進化

属性値コンストラクタを使用することにより、型に対して独自のコンストラクタを定義する必要がなくなります。ただし、型に宣言されたすべての属性に対して値を指定する必要があり、指定しない場合はコンストラクタ・コールのコンパイルに失敗します。

ユーザー定義コンストラクタと異なり、特に属性値コンストラクタは暗黙的でコードに表示されないため、後で型を進化させる場合、この要件によって問題が発生することがあります。型の属性を変更した場合は、その型の属性値コンストラクタも変更されます。属性を追加した場合、更新された属性値コンストラクタは、新しい属性に対する値が指定されるものとみなします。それ以外の場合は、既存のコード内の属性値コンストラクタへのコールが失敗します。

「型進化」を参照してください。

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

ユーザー定義コンストラクタは、属性値コンストラクタと異なり、型の各属性に対する値を明示的に設定する必要がありません。ユーザー定義コンストラクタは、任意の型の任意の数の引数を取ることができ、これらの引数は型の属性に直接マップする必要がありません。コンストラクタを定義する場合、属性を任意の適切な値に初期化できます。値が指定されない属性は、システムによってNULLに初期化されます。

たとえば、属性を追加して型を進化させる場合、その型に対するユーザー定義コンストラクタへのコールは変更する必要がありません。型を進化させる場合、ユーザー定義コンストラクタは自動的に変更されないため、シグネチャは同じままです。ただし、新しい属性をNULLに初期化しない場合は、コンストラクタの定義の変更が必要になることがあります。

ユーザー定義コンストラクタの定義および実装

ユーザー定義コンストラクタは、通常のメソッドと同様に型本体に定義します。ユーザー定義コンストラクタの宣言および定義は、CONSTRUCTOR FUNCTION句を使用し、RETURN SELF AS RESULT句で終了します。

型のコンストラクタには、型と同じ名前を使用する必要があります。例8-10では、shape型の2つのコンストラクタ・ファンクションを定義します。例に示すとおり、異なるシグネチャを持つ複数のバージョンを定義することにより、ユーザー定義コンストラクタをオーバーロードできます。

例8-10 ユーザー定義コンストラクタの定義および実装

CREATE TYPE shape AS OBJECT (
name VARCHAR2(30),
area NUMBER,
CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2)
RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2,
area NUMBER) RETURN SELF AS RESULT
) NOT FINAL;
/

CREATE TYPE BODY shape AS
CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2)
RETURN SELF AS RESULT IS
BEGIN
SELF.name := name;
SELF.area := 0;
RETURN;
END;
CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2,
area NUMBER) RETURN SELF AS RESULT IS
BEGIN
SELF.name := name;
SELF.area := area;
RETURN;
END;
END;
/

ユーザー定義コンストラクタには、暗黙的な第1パラメータSELFがあります。ユーザー定義コンストラクタの宣言では、このパラメータの指定はオプションです。指定する場合、このパラメータのモードはIN OUTとして宣言する必要があります。

必須句RETURN SELF AS RESULTによって、戻されるインスタンスの最も狭い意味での型は、必ずSELF引数の最も狭い意味での型と同じになります。コンストラクタの場合、この型は、コンストラクタが定義された型です。shapeコンストラクタへのコールに対するSELF引数の最も狭い意味での型がshapeの場合、この句によってshapeコンストラクタからはshapeのサブタイプのインスタンスではなくshapeのインスタンスが必ず戻されます。

コンストラクタ・ファンクションがコールされると、システムはSELF引数の属性をNULLに初期化します。例8-10のSELF.nameなど、ファンクション本体で初期化される後続の属性名は、コンストラクタ・ファンクションの引数の名前と区別するために、SELFで修飾できます(これらの名前が同一の場合)。引数の名前が異なる場合、この修飾は不要です。

例に示すとおり、ファンクション本体には、明示的なreturn;を含める必要があります。ただし、returnキーワードの後に、return式を続けることはできません。システムは、新しく作成されたSELFインスタンスを自動的に戻します。

ユーザー定義コンストラクタは、PL/SQL、CまたはJavaで実装できます。

コンストラクタのオーバーロードおよび隠蔽

他の型のメソッドと同様、ユーザー定義コンストラクタもオーバーロードできます。

ユーザー定義コンストラクタは継承されないため、スーパータイプで定義されたユーザー定義コンストラクタはサブタイプに隠蔽できません。ただし、ユーザー定義コンストラクタのシグネチャが属性値コンストラクタのシグネチャと完全に一致する場合、ユーザー定義コンストラクタはその型の属性値コンストラクタを隠蔽し、これを置き換えます。シグネチャが一致するには、ユーザー定義コンストラクタのパラメータ(暗黙的なSELFパラメータの後)の名前と型が、その型の属性の名前と型と同じである必要があります。ユーザー定義コンストラクタのパラメータ(暗黙的なSELFパラメータの後)のモードは、必ずINにしてください。

同じ名前とシグネチャを持つユーザー定義コンストラクタによって属性値コンストラクタが隠蔽されていない場合は、継続して属性値コンストラクタをコールできます。

たとえば、属性の追加により型が進化する場合は、型の属性値コンストラクタのシグネチャもそれに対応して変更することに注意してください。これによって、以前に隠蔽されていた属性値コンストラクタが再度使用可能になります。

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

他のすべてのファンクションと同様にユーザー定義コンストラクタをコールし、通常のファンクションが使用できるすべての場所で使用できます。

SELF引数は、暗黙的に渡され、明示的に渡されません。つまり、次のように使用することはできません。

NEW constructor(instance, argument_list)

CREATEまたはALTER TABLE文のDEFAULT句には、ユーザー定義コンストラクタは指定できませんが、属性値コンストラクタは指定できます。属性値コンストラクタの引数には、PL/SQLファンクションまたは他の列(疑似列LEVEL、PRIOR、ROWNUMなど)の参照、あるいは完全に指定されていない日付定数の参照を含めることはできません。CHECK制約式についても同様です。表の作成中または変更中に、属性値コンストラクタはCHECK制約式の一部として使用できますが、ユーザー定義コンストラクタは使用できません。

SQLでは、引数を持たないコンストラクタ・コールについても、カッコを付ける必要があります。PL/SQLでは、引数を持たないコンストラクタを起動する場合、カッコはオプションです。ただし、カッコを付けた方が、コンストラクタ・コールがファンクション・コールであることがより明確になります。次のPL/SQL例では、新しいshapeを作成するためのコンストラクタ・コールのカッコが省略されています。

shape s := NEW my_schema.shape;

NEWキーワードおよびスキーマ名はオプションで使用してください。

例8-11では、例8-10で作成した型の下にサブタイプを作成し、ユーザー定義コンストラクタをコールする例を示します。

例8-11 ユーザー定義コンストラクタのコール

-- Requires Ex. 8-10
CREATE TYPE rectangle UNDER shape (
len NUMBER,
wth NUMBER,
CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
name VARCHAR2, len NUMBER, wth NUMBER) RETURN SELF as RESULT,
CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
name VARCHAR2, side NUMBER) RETURN SELF as RESULT);
/
SHOW ERRORS
CREATE TYPE BODY rectangle IS
CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
name VARCHAR2, len NUMBER, wth NUMBER) RETURN  SELF AS RESULT IS
BEGIN
SELF.name := name;
SELF.area := len*wth;
SELF.len := len;
SELF.wth := wth;
RETURN ;
END;
CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
name VARCHAR2, side NUMBER) RETURN  SELF AS RESULT IS
BEGIN
SELF.name := name;
SELF.area := side * side;
SELF.len := side;
SELF.wth := side;
RETURN ;
END;
END;
/

CREATE TABLE shape_table OF shape;
INSERT INTO shape_table VALUES(shape('shape1'));
INSERT INTO shape_table VALUES(shape('shape2', 20));
INSERT INTO shape_table VALUES(rectangle('rectangle', 2, 5));
INSERT INTO shape_table VALUES(rectangle('quadrangle', 12, 3));
INSERT INTO shape_table VALUES(rectangle('square', 12));

次の問合せでは、shape_table内の行を選択します。

SELECT VALUE(s) FROM shape_table s;

VALUE(S)(NAME, AREA)
---------------------------------------------
SHAPE('shape1', 0)
SHAPE('shape2', 20)
RECTANGLE('rectangle', 10, 2, 5)
RECTANGLE('quadrangle', 36, 12, 3)
RECTANGLE('square', 144, 12, 12)

次のPL/SQLコードは、コンストラクタをコールします。

s shape := NEW shape('void');

SQLJオブジェクト型のコンストラクタ

SQLJオブジェクト型は、JavaクラスにマップされるSQLオブジェクト型です。SQLJオブジェクト型は属性値コンストラクタを持ちます。このオブジェクト型は、参照されたJavaクラスでコンストラクタにマップされるユーザー定義コンストラクタを持つこともできます。

例8-12 SQLJオブジェクトの作成

CREATE TYPE address AS OBJECT
EXTERNAL NAME 'university.address' LANGUAGE JAVA
USING SQLData(
street   VARCHAR2(100) EXTERNAL NAME 'street',
city     VARCHAR2(50)  EXTERNAL NAME 'city',
state    VARCHAR2(50)  EXTERNAL NAME 'state',
zipcode  NUMBER        EXTERNAL NAME 'zipcode',
CONSTRUCTOR FUNCTION address (SELF IN OUT NOCOPY address, street VARCHAR2,
city VARCHAR2, state VARCHAR2, zipcode NUMBER)
RETURN SELF AS RESULT AS LANGUAGE JAVA
NAME  'university.address (java.lang.String, java.lang.String,
java.lang.String, int) return address');
/

シリアル化表現のSQLJ型は、ユーザー定義コンストラクタのみ持つことができます。SQLJ型のオブジェクトの内部表現は、SQLにとって不透明であるため、SQLJ型に属性値コンストラクタは使用できません。

一時型および汎用型

Oracle Databaseには、型の記述、データ・インスタンス、およびオブジェクト型やコレクション型を含むその他のSQL型のデータ・インスタンスの集合の動的なカプセル化およびアクセスを可能にする3つの特殊なSQLデータ型があります。この3つの型は、匿名のコレクション型を含めた匿名型の作成にも使用できます。

この3つのSQL型は、不透明型として実装されます。つまり、これらの型の内部構造は、データベースには認識されません。不透明型のデータへの問合せは、目的に合ったファンクション(通常は3GLルーチン)を実装することによってのみ実行されます。Oracle Databaseは、そのようなファンクションを実装するためにOCIとPL/SQL APIの両方を提供しています。

一時型の構造は、データベースにとって不透明です。そのため、それらは永続的に格納することはできません。一時型の列は作成できず、永続型の属性にできません。

表8-2で、この3つの汎用SQL型を説明します。

表8-2 汎用SQL型

型

説明

SYS.ANYTYPE

型記述型。SYS.ANYTYPEには、名前が付いているか付いていないかにかかわらず、オブジェクト型およびコレクション型を含めた、任意のSQL型の型記述を含めることができます。

ANYTYPEには、永続型の型の記述を含めることができますが、ANYTYPE自体は一時型です。つまり、ANYTYPE自体の値がデータベースに自動的に格納されることはありません。永続型を作成するには、SQLからCREATE TYPE文を使用します。

SYS.ANYDATA

自己記述的データ・インスタンスの型。SYS.ANYDATAには、与えられた型のインスタンス、データ、およびその型の記述が含まれています。SYS.ANYDATAは、この意味で自己記述的です。ANYDATAは、データベースに永続的に格納できます。

次のものはANYDATA列に格納できません。

- ANYDATAまたはXMLTYPEなどの別の不透明な型

- LOB型(BLOB/CLOB/NCLOB)

- 4Kより大きい最大サイズのVARRAY型

- 前述の型のいずれかを含むADT

- 一時型

SYS.ANYDATASET

自己記述的なデータ集合の型。SYS.ANYDATASETには、与えられた型の記述、およびその型のデータ・インスタンスの集合が含まれています。ANYDATASETは、データベースに永続的に格納できます。

次のものはANYDATASET列に格納できません。

- ANYDATAまたはXMLTYPEなどの別の不透明な型

- LOB型(BLOB/CLOB/NCLOB)

- 4Kより大きい最大サイズのVARRAY型

- 前述の型のいずれかを含むADT

- 一時型

この3つの型はそれぞれ、データベースに対してネイティブな組込み型や、名前の有無にかかわらずオブジェクト型およびコレクション型と併用できます。型は、型記述、単独インスタンスおよび他の型のインスタンス・セットを動的に操作するための汎用的な方法を提供します。APIを使用すると、あらゆる種類の型について一時的なANYTYPE記述を作成できます。同様に、任意のSQL型のデータ値を作成するかANYDATAに変換(キャスト)し、ANYDATAをSQL型に変換できます。さらに、値セットとANYDATASETの場合も同様です。

汎用型は、ストアド・プロシージャを使用した作業を簡単にします。汎用型を使用して、標準型の記述およびデータをカプセル化し、カプセル化された情報を汎用型のパラメータに渡せます。プロシージャ本体では、カプセル化されたデータおよび任意の型の型記述の処理方法を詳細に記述できます。

また、基礎となる様々な型のカプセル化されたデータを、型ANYDATAまたはANYDATASETの単一の表の列に格納することもできます。たとえば、ANYDATAをアドバンスト・キューイングと併用して、異質な型のデータのキューイングをモデル化できます。基礎となるデータ型のデータは、他の任意のデータ同様に、問合せを実行できます。

例8-13では、SYS.ANYDATAに組み込まれたメソッドを使用して、SYS.ANYDATA表列に格納されているデータの情報にアクセスするPL/SQLプロシージャを定義して実行します。

例8-13 SYS.ANYDATAの使用

CREATE OR REPLACE TYPE dogowner AS OBJECT (
ownerno NUMBER, ownername VARCHAR2(10) );
/
CREATE OR REPLACE TYPE dog AS OBJECT (
breed VARCHAR2(10), dogname VARCHAR2(10) );
/
CREATE TABLE mytab ( id NUMBER, data SYS.ANYDATA );
INSERT INTO mytab VALUES ( 1, SYS.ANYDATA.ConvertNumber (5) );
INSERT INTO mytab VALUES ( 2, SYS.ANYDATA.ConvertObject (
dogowner ( 5555, 'John') ) );
commit;

CREATE OR REPLACE procedure P IS
CURSOR cur IS SELECT id, data FROM mytab;

v_id mytab.id%TYPE;
v_data mytab.data%TYPE;
v_type SYS.ANYTYPE;
v_typecode PLS_INTEGER;
v_typename VARCHAR2(60);
v_dummy PLS_INTEGER;
v_n NUMBER;
v_dogowner dogowner;
non_null_anytype_for_NUMBER exception;
unknown_typename exception;

BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id, v_data;
EXIT WHEN cur%NOTFOUND;
v_typecode := v_data.GetType ( v_type /* OUT */ );
CASE v_typecode
WHEN Dbms_Types.Typecode_NUMBER THEN
IF v_type IS NOT NULL
THEN RAISE non_null_anytype_for_NUMBER; END IF;
v_dummy := v_data.GetNUMBER ( v_n /* OUT */ );
Dbms_Output.Put_Line (
To_Char(v_id) || ': NUMBER = ' || To_Char(v_n) );
WHEN Dbms_Types.Typecode_Object THEN
v_typename := v_data.GetTypeName();
IF v_typename NOT IN ( 'HR.DOGOWNER' )
THEN RAISE unknown_typename; END IF;
v_dummy := v_data.GetObject ( v_dogowner /* OUT */ );
Dbms_Output.Put_Line (
To_Char(v_id) || ': user-defined type = ' || v_typename ||
'(' || v_dogowner.ownerno || ', ' || v_dogowner.ownername || ' )' );
END CASE;
END LOOP;
CLOSE cur;

EXCEPTION
WHEN non_null_anytype_for_NUMBER THEN
RAISE_Application_Error ( -20000,
'Paradox: the return AnyType instance FROM GetType ' ||
'should be NULL for all but user-defined types' );
WHEN unknown_typename THEN
RAISE_Application_Error ( -20000,
'Unknown user-defined type ' || v_typename ||
' - program written to handle only HR.DOGOWNER' );
END;
/

SELECT t.data.gettypename() FROM mytab t;
SET SERVEROUTPUT ON;
EXEC P;

前述にコード例の問合せおよびプロシージャPにより、次のような出力が生成されます。

T.DATA.GETTYPENAME()
-------------------------------------------------------------
SYS.NUMBER
HR.DOGOWNER

1: NUMBER = 5
2: user-defined type = HR.DOGOWNER(5555, John )

前述の3つの汎用SQL型に対応するのが、それらをモデル化するOCI型です。各OCI型は、それぞれの型の作成およびアクセスに使用する関数のセットを備えています。

- OCIType: SYS.ANYTYPEに対応しています。

- OCIAnyData: SYS.ANYDATAに対応しています。

- OCIAnyDataSet: SYS.ANYDATASETに対応しています。

関連項目:

- OCIType、OCIAnyData、OCIAnyDataSet APIおよびそれらの使用方法の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- ANYTYPE、ANYDATAおよびANYDATASET型へのインタフェースの詳細と、ANYTYPE、ANYDATAおよびANYDATASETとともに使用するDBMS_TYPESパッケージ(組込み型およびユーザー定義型の定数を定義)の詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

ユーザー定義集計ファンクション

Oracle Databaseは、レコード集合に対する操作に使用する、MAX、MINおよびSUMをはじめとする数多くの定義済集計ファンクションを提供しています。これらの定義済集計ファンクションは、スカラー・データに対してのみ使用できます。ただし、これらのファンクションのカスタム実装を独自に作成することもできれば、複雑なデータ(たとえば、オブジェクト型、不透明型、LOB型を使用して格納されているマルチメディア・データなど)に対して使用する新しい集計ファンクションを定義することもできます。

ユーザー定義集計ファンクションは、Oracleデータベースの組込み集計ファンクションと同様に、SQL DML文で使用されます。このようなファンクションがサーバーに登録されていると、ネイティブのルーチンではなく、ユーザーが定義した集計ルーチンがコールされます。

ユーザー定義集計ファンクションは、スカラー・データに対しても使用できます。たとえば、財務アプリケーションまたは科学アプリケーションに対応付けられた複雑な統計データを処理するために特殊な集計ファンクションを実装すると効果的な場合があります。

ユーザー定義集計ファンクションは、拡張フレームワークの機能です。それらの実装には、ODCIAggregateインタフェース・ルーチンを使用します。

関連項目:
ODCIAggregateインタフェース・ルーチンを使用して、ユーザー定義集計ファンクションを実装する方法については、『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください。

ロケータでネストした表のパフォーマンスを向上させる方法

ネストした表のロケータを使用して、データの取得時にパフォーマンスを向上できます。

コレクション型は、C++やJavaなどの言語でのシステム固有の型または構造へ直接マップすることはありません。これらの言語を使用しているアプリケーションは、OCIなどのOracleデータベース・インタフェースを介して、コレクションの内容にアクセスする必要があります。

一般に、クライアントが(オブジェクトをフェッチすることによって)ネストした表に明示的または暗黙的にアクセスすると、コレクション値全体がクライアント・プロセスに戻されます。パフォーマンス上の理由から、クライアントは、コレクションの内容全体を取り出すのを遅延または回避する場合があります。Oracleデータベースでは、ネストした表の実際の値ではなくロケータを使用することによって、これに対処します。実際にコレクションの内容にアクセスが行われたときは、その内容がクライアントに自動的に転送されます。

ネストした表のロケータは、コレクション値へのハンドルに似ています。検索実行時のデータベース・スナップショットを確保することで、ネストした表の値またはコピー・セマンティクスを保とうとします。スナップショットによって、コレクション要素がロケータを使用してフェッチされたときに、データベースがネストした表の値の正しいインスタンスを取り出せるようになります。ロケータの有効範囲は1つのセッションにかぎられ、複数のセッションにまたがって使用することはできません。データベース・スナップショットが使用されているため、ネストした表の更新率が高い場合は、「スナップショットが古すぎます」というエラーが発生する場合があります。LOBロケータとは異なり、ネストした表のロケータは純粋なロケータであり、コレクション・インスタンスを変更するためには使用できません。

関連項目:
詳細は、「ネストした表のロケータ」を参照してください。

9 Oracleオブジェクトの設計上の考慮点

この章では、Oracleのオブジェクト・リレーショナル・モデルの実装およびパフォーマンス特性について説明します。ここで説明する内容は、論理データ・モデルをOracleの物理的な実装にマップしたり、オブジェクト指向機能を使用するアプリケーションを開発する場合に役立ちます。

内容は次のとおりです。

- オブジェクトの記憶域上の一般的な考慮点

- オブジェクト比較のパフォーマンス

- REFの設計上の考慮点

- コレクションの設計上の考慮点

- メソッドの設計上の考慮点

- 実行者権限を使用した再利用コードの作成

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

- オブジェクト表およびオブジェクト列のレプリケーション

- オブジェクトに対する制約

- 型進化に関する考慮点

- Oracleオブジェクトでのパラレル問合せ

- 設計上の考慮点のヒントおよび技法

オブジェクトの記憶域上の一般的な考慮点

この項では、様々なオブジェクト型の記憶域に関する一般的な考慮点を説明します。

この項の内容は次のとおりです。

- 列または行としてのオブジェクトの格納

- オブジェクト識別子(OID)の記憶域上の考慮点

列または行としてのオブジェクトの格納

オブジェクトは、列オブジェクトとしてリレーショナル表に格納するか、または行オブジェクトとしてオブジェクト表に格納できます。包含しているリレーショナル・データベースの外で意味を持つオブジェクトは、オブジェクト表内で行オブジェクトとして参照できるようにする必要があります。そうしない場合、それらのオブジェクトはリレーショナル表に列オブジェクトとして格納する必要があります。

表記憶域の概要は、「オブジェクトを表に格納する方法」を参照してください。

この項の内容は次のとおりです。

- リレーショナル表の列オブジェクトの記憶域

- オブジェクト表の行オブジェクトの記憶域

リレーショナル表の列オブジェクトの記憶域

列オブジェクトの記憶域は、1つの集合としてオブジェクトを形成する、同等のスカラー列集合の記憶域と似ています。違いは、非コレクション列オブジェクトのアトミックNULL値およびその埋込みオブジェクト属性をメンテナンスするオーバーヘッドが加わることです。これらの値はNULLインジケータと呼ばれ(NULLイメージと呼ばれることもあります)、それぞれの列オブジェクトがNULLかどうか、およびその埋込みオブジェクト属性それぞれがNULLかどうかを指定します。

NULLインジケータは、列オブジェクトのスカラー属性がNULLかどうかは指定しませんので注意してください。Oracleでは、別の方法でスカラー属性がNULLかどうかを判断します。

ある組織の構成員の識別番号、名前、住所および電話番号を持つ表を考えてみます。名前、住所および電話番号を保持するための3種類のオブジェクト型と、名前オブジェクトと住所オブジェクトが含まれるオブジェクトemployee_objtypを作成できます。各人が複数の電話番号を持つ場合があるため、電話番号オブジェクト型に基づいてネストした表型を作成する必要があります。

まず、例9-1のSQL文を入力して、電話番号オブジェクトに対して4つのオブジェクト型と1つの表を作成します。

例9-1 リレーショナル表の列のオブジェクト型の作成

CREATE TYPE name_objtyp AS OBJECT (
first       VARCHAR2(15),
middle      VARCHAR2(15),
last        VARCHAR2(15));
/
CREATE TYPE address_objtyp AS OBJECT (
street       VARCHAR2(200),
city         VARCHAR2(200),
state        VARCHAR2(2),
zipcode      VARCHAR2(20));
NOT FINAL;
/
CREATE TYPE phone_objtyp AS OBJECT (
location     VARCHAR2(15),
num          VARCHAR2(14));
/

CREATE TYPE employee_objtyp AS OBJECT (
name name_objtyp;
address address_objtyp;
/

CREATE TYPE phone_ntabtyp AS TABLE OF phone_objtyp;
/

関連項目:
ネストした表の詳細は、「ネストした表の設計上の考慮点」を参照してください。

次に、例9-2のSQL文を使用して、組織の構成員の情報を保持する表を作成します。この文により、組織の構成員のIDも作成されます。

例9-2 列オブジェクトを含む表の作成

CREATE TABLE people_reltab (
id            NUMBER(4)   CONSTRAINT pk_people_reltab PRIMARY KEY,
employee      employee_objtyp
phones_ntab   phone_ntabtyp)
NESTED TABLE  phones_ntab STORE AS phone_store_ntab;

図9-1 people_reltabリレーショナル表の表現

people_reltab表には、employeeおよびphones_ntabの2つの列オブジェクトがあります。phones_ntab列オブジェクトは、ネストした表(列オブジェクトのコレクション型)です。

people_reltab表の各オブジェクトの記憶域は、オブジェクトの属性の記憶域にNULLインジケータのオーバーヘッドを加えたものです。

オブジェクトおよびその埋込みオブジェクト属性のNULLインジケータは、それぞれ1ビットずつ占有します。したがって、(すべてのネスト・レベルのオブジェクトを含めて)n個の埋込みオブジェクト属性を持つオブジェクトには、記憶域のオーバーヘッドがCEIL(n/8)バイトあります。非コレクション列オブジェクト(name_objおよびaddress_obj)にはそれぞれNULLインジケータ列が1つずつあります。1ビットがオブジェクトそのものを表し、それがCEIL(1/8)または1と解釈されるため、NULLインジケータ列の長さは1バイトです。

NULLインジケータのサイズが1バイトなので、people_reltab表の各行のNULL情報のオーバーヘッドは2バイト(オブジェクト列ごとに1バイトずつ)になります。

非コレクション・オブジェクトはいずれも、FINALであるかどうかにかかわらず、NULLインジケータ列を持ちます。これらの例では、列はFINALです。

関連項目:
CEILの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

オブジェクト表の行オブジェクトの記憶域

行オブジェクトは、オブジェクト表に格納されます。オブジェクト表は、オブジェクトを格納し、このオブジェクト属性に対してリレーショナル表と同様にアクセスできるリレーショナル・ビューを提供する特殊な表です。オブジェクト表は、オブジェクト表に格納された、オブジェクトの最上位の属性に対応するデータ型の列を持つリレーショナル表と、論理的、物理的に類似しています。主な違いは、オブジェクト表には、追加のオブジェクト識別子(OID)の列および索引をオプションで含めることができることです。

オブジェクト識別子(OID)の記憶域上の考慮点

この項では、オブジェクト表の行オブジェクトの2種類のオブジェクト識別子を示し、それらがどのように格納および参照されるかを説明します。

オブジェクト識別子(OID)を利用することで、対応する行オブジェクトを、他のオブジェクトまたはリレーショナル表間で参照できます。このような参照は、REFと呼ばれる組込みデータ型によって表されます。REFは、オブジェクト識別子(OID)を使用して行オブジェクトを指します。

システムによって生成されるOIDまたは主キー・ベースのOIDのどちらかを使用できます。

関連項目:
「行オブジェクトの参照の使用」

システム生成のオブジェクト識別子(OID)

システム生成のOIDは、オブジェクト表の行オブジェクトのデフォルトです。

システム生成の一意のOID (16バイト長)が、各行オブジェクトに割り当てられ、このOIDは、効率的なOIDベースの検索ができるように自動的に索引付けされます。OID列は、16バイトの主キー列を別に持つのと同じ効果があります。分散環境では、システム生成の一意の識別子によって、オブジェクトが明確に識別されます。

オブジェクト識別子列は、Oracleが行オブジェクトの参照を構成するために使用する非表示の列です。Oracleでは、オブジェクト識別子の内部構造へのアクセスは提供されていません。この構造は随時変更される可能性があります。アプリケーションが関連するのは、オブジェクトのフェッチおよびナビゲートにオブジェクト参照を使用する場合のみです。

主キー・ベースのオブジェクト識別子(OID)

Oracleでは、主キー列が存在する場合、行オブジェクトの主キー値をそのオブジェクト識別子として指定するというオプションを使用できます。

システム生成のOIDを使用せず、CREATE TABLE文をこの句(OBJECT IDENTIFIER IS PRIMARY KEY)とともに使用します。これにより、システムで主キー列を表のオブジェクトのOIDとして使用することを指定します。この方法で、既存の列をオブジェクトのOIDとして使用することも、Oracleによって生成されたグローバルに一意な16バイトのOIDよりも小さい、アプリケーションによって生成されたOIDを使用することもできます。

関連項目:
OBJECT IDENTIFER構文の詳細は、 『Oracle Database SQL言語リファレンス』を参照してください。

リレーショナル表の外部キーと同様の方法で、これらの行オブジェクトの参照を格納する列に対して、参照整合性を確保できます。

注意:
主キー・ベースの各OIDは、ローカルに一意です(グローバルに一意である必要はありません)。グローバルに一意の識別子が必要な場合は、主キーがグローバルに一意であることを保証するか、またはシステムによって生成されるOIDを使用する必要があります。

システム生成のOIDと主キー・ベースのOID

主キー・ベースの識別子を利用することで、オブジェクト表へのデータのロードを高速かつ容易に行うことができます。それに対して、システム生成のオブジェクト識別子は、それらの参照も格納される場合は特に、ユーザーが指定したキーを使用して再度マップする必要があります。オブジェクト表に対して、システムが生成するOIDを使用する場合、OracleがこれらのOIDを格納する列の索引をメンテナンスします。システム生成のOIDには、この索引用の追加の記憶域と、行オブジェクト1つにつき16バイトの追加の記憶域が必要です。

ただし、各主キーのサイズが16バイトを超え、数多くのREFがある場合は、各REFのサイズは主キーと同じであるため、主キー・ベースのOIDを使用すると、システムによって生成されるOIDより多くの領域が必要になる場合があります。

オブジェクト比較のパフォーマンス

オブジェクトを比較するには、マップ・メソッドまたはオーダー・メソッドを起動します。マップ・メソッドは、オブジェクトの順序付けを行う際にオブジェクトをスカラー値に変換します。マップ・メソッドを使用するとオブジェクトの順序付けが効率的に行われるため、マップ・メソッドの使用をお薦めします。

注意:
どのオブジェクト型でも、マップ・メソッドまたはオーダー・メソッドのどちらか一方を実装できますが、両方は実装できません。どちらも必須ではありません。

ORDER BYまたはGROUP BYプロセスを使用してオブジェクトをソートするとき、オブジェクトのマップ方法がパフォーマンスに大きく影響します。オブジェクトを他のオブジェクトに何度も比較する必要がある場合があり、オブジェクトを最初にスカラー値にマップできると(マップ・メソッド)、効率が大幅に向上します。比較セマンティクスが非常に複雑な場合、またはオブジェクトを比較用のスカラー値にマップできない場合、指定された2つのオブジェクトに対して、オブジェクト作成者によって決定された順序を戻すオーダー・メソッドを定義できます。オーダー・メソッドは、マップ・メソッドほど効率的でないため、オーダー・メソッドを使用するとパフォーマンスが低下する場合があります。

4つの文字属性、street、city、stateおよびzipcodeで構成されるオブジェクト型addressについて考えてみます。この場合は、各オブジェクトは簡単にスカラー値に変換できるため、最も効率的な比較メソッドはマップ・メソッドです。たとえば、州によってすべてのオブジェクトを順序付けるマップ・メソッドを定義できます。

一方、イメージなどのバイナリ・オブジェクトを比較する場合を考えてみます。この場合、比較セマンティクスが複雑すぎてマップ・メソッドは使用できない可能性があります。その場合は、オーダー・メソッドを使用して比較を実行できます。たとえば、各イメージの明度またはピクセル数によってイメージを比較するオーダー・メソッドを作成できます。

マップ・メソッドもオーダー・メソッドもないオブジェクト型のオブジェクトに対しては、等価比較のみが可能です。この場合、Oracleでは、対応するオブジェクト属性のフィールド同士が定義順に比較されます。いずれかのフィールドの比較結果が不一致となると、その時点で、FALSE値が戻されます。すべてのフィールドの比較において一致が確認されると、TRUE値が戻されます。ただし、オブジェクトがLOB属性またはANYDATA属性を持つ場合、フィールド・ベースのオブジェクトの比較は行われません。このようなオブジェクトの比較を実行するためにはマップ・メソッドまたはオーダー・メソッドが必要です。

REFの設計上の考慮点

この項では、REFを使用した作業での考慮点を説明します。

- REFの記憶域サイズ

- REF列に対する整合性制約

- 有効範囲付きREFのパフォーマンスおよび記憶域に関する考慮点

- WITH ROWIDオプションを使用したオブジェクト・アクセスの高速化

REFの記憶域サイズ

REFには、次の3つの論理コンポーネントが含まれています。

- 参照されるオブジェクトのOID。システムによって生成されるOIDの長さは16バイトです。主キー・ベースのOIDのサイズは、主キー列のサイズによって決まります。

- 参照されるオブジェクトが含まれている表またはビューのOID。この長さは16バイトです。

- ROWIDヒント。この長さは10バイトです。

REF列に対する整合性制約

REF列に対する参照整合性制約によって、そのREFに対応する行オブジェクトが存在することが保証されます。REFに対する参照整合性制約によって、リレーショナル・データに対して主キー/外部キー関連を指定した場合と同じ関連が生成されます。参照整合性制約は、REFに対応する行オブジェクトが存在することを保証する唯一の方法であるため、通常はできるだけ参照整合性制約を使用してください。ただし、ネストした表にあるREFに対しては、参照整合性制約を指定できません。

有効範囲付きREFのパフォーマンスおよび記憶域に関する考慮点

有効範囲付きREFには、指定したオブジェクト表の参照のみを含む、という制約があります。有効範囲付きREFは、REFとなる列型、コレクション要素、またはオブジェクト型属性を宣言するときに指定できます。

有効範囲付きREFの方が格納する際に効率的なため、通常は、有効範囲なしのREFではなく、有効範囲付きREFを使用してください。有効範囲なしのREFを格納するには、36バイト以上(ROWIDを使用する場合はさらに多く)必要ですが、有効範囲付きREFの格納には、ターゲット・オブジェクトのOIDと同じだけの領域のみを必要とするため、参照されるOIDがシステムによって生成されたOIDか、主キー・ベースのOIDかによって、16バイト未満で格納できる場合もあります。システムによって生成されたOIDの場合は、16バイト必要です。主キー・ベース(PKベース)のOIDの場合は、主キー値を格納できるだけの領域が必要ですが、これは16バイト未満の場合もあります。ただし、PKベースのOIDに対するREFは、選択時に動的な構成が必要なので、システムによって生成されたOIDに対するREFの場合と比較して、多くのメモリー領域が必要となる場合があります。

有効範囲付きREFは記憶域が少なくてすむうえに、オプティマイザによって、有効範囲付きREFを参照解除する問合せを最適化して、さらに効率的な結合にすることができます。有効範囲なしのREFに対しては、問合せの最適化時に、有効範囲なしのREFをどの表に含めるべきか、オプティマイザによる判断が不可能なため、この最適化はできません。

参照整合性制約とは異なり、有効範囲付きREFによっては、参照される行オブジェクトの存在は保証されません。保証されるのは、参照されるオブジェクト表の存在のみです。したがって、行オブジェクトに対して有効範囲付きREFを指定した後でその行オブジェクトを削除すると、参照対象となるオブジェクトがなくなるため、その有効範囲付きREFは、参照先がないREFになります。

注意:
参照整合性制約には、暗黙的に有効範囲が付きます。

アプリケーション設計上、参照されるオブジェクトが複数の表に分散している場合は、有効範囲なしのREFが便利です。ROWIDヒントは有効範囲付きREFに対しては無視されるため、「WITH ROWIDオプションを使用したオブジェクト・アクセスの高速化」で説明するとおり、ROWIDヒントによるパフォーマンスの向上の方が、有効範囲付きREFを使用した場合の記憶域の節約および問合せの最適化よりも重要である場合は、有効範囲なしのREFを使用してください。

有効範囲付きREFの索引付け

CREATE INDEXコマンドを使用して、有効範囲付きREF列に対する索引を作成できます。作成した索引を使用して、有効範囲付きREFを参照解除する問合せを効率的に評価できます。このような問合せは暗黙的に結合に変換されます。Oracleでは、ある種の問合せに対しては、有効範囲付きREF列の索引を使用して結合を効率的に評価できます。

たとえば、オブジェクト型address_objtypを使用してaddress_objtabという名前のオブジェクト表を作成するとします。

CREATE TABLE address_objtab OF address_objtyp ;

住所に対してREFが使用されること以外は、例9-2に示したpeople_reltab表と同じ定義を持つpeople_reltab2表を作成できます。次に、address_ref列に対して索引を作成できます。

例9-3 有効範囲付きREF列に対する索引の作成

CREATE TABLE people_reltab2 (
id            NUMBER(4)   CONSTRAINT pk_people_reltab2 PRIMARY KEY,
name_obj      name_objtyp,
address_ref   REF address_objtyp SCOPE IS address_objtab,
phones_ntab   phone_ntabtyp)
NESTED TABLE  phones_ntab STORE AS phone_store_ntab2 ;

CREATE INDEX address_ref_idx ON people_reltab2 (address_ref) ;

次の問合せでaddress_refが参照解除されます。

SELECT id FROM people_reltab2 p
WHERE p.address_ref.state = 'CA' ;

この問合せの実行時には、効率的に評価を行うためにaddress_ref_idx索引が使用されます。ここで、address_refは、address_objtabオブジェクト表に格納される住所の参照を格納した有効範囲付きREF列です。前述の問合せは、結合を持つ問合せに暗黙的に変換されます。

SELECT p.id FROM people_reltab2 p, address_objtab a
WHERE p.address_ref = REF(a) AND a.state = 'CA' ;

Oracle問合せオプティマイザによって、address_objtabを外部表としてネステッド・ループ結合を実行し、有効範囲付きREF列address_refの索引を使用して、一致する住所を検索する計画が作成される場合があります。

WITH ROWIDオプションを使用したオブジェクト・アクセスの高速化

REF列に対してWITH ROWIDオプションが指定されていると、REFで参照されるオブジェクトのROWIDがメンテナンスされます。こうしておくと、REFに含まれているROWIDを直接使用して参照されるオブジェクトの検索が実行できるため、OID索引からROWIDをフェッチする手間が省けます。したがって、ROWIDヒントを指定するには、WITH ROWIDオプションを使用してください。ROWIDを含めることによって、REFの記憶域要件が10バイト増加するため、これをメンテナンスするにはそれだけ多くの記憶域が必要です。

OID索引検索を迂回すると、アプリケーションでのREFを使用した操作(ナビゲーショナル・アクセス)のパフォーマンスが向上します。実際のパフォーマンス向上率は、次の要因によって、アプリケーションごとに異なります。

- OID索引の大きさ

- OID索引がバッファ・キャッシュにキャッシュされているかどうか

- アプリケーションが実行するREFを使用した操作数

WITH ROWIDオプションを使用する場合、REF内のOIDで行オブジェクトのOIDがチェックされるため、このオプションは単なるヒントとなります。2つのOIDが一致しない場合は、OID索引がかわりに使用されます。ROWIDヒントは、有効範囲付きREF、参照整合性制約付きREFおよび主キー・ベースのREFに対しては利用できません。

コレクションの設計上の考慮点

この項では、コレクションを使用した作業での考慮点を説明します。

- ネストを解除する問合せを使用したリレーショナル形式でのオブジェクト・データの表示

- VARRAYの記憶域上の考慮点

- VARRAYおよびネストした表のパフォーマンス

- ネストした表の設計上の考慮点

- マルチレベル・コレクションの設計上の考慮点

ネストを解除する問合せを使用したリレーショナル形式でのオブジェクト・データの表示

コレクションに対してネストを解除する問合せを実行することで、データをフラットな(リレーショナルな)形式で表示できます。ネストを解除する問合せは、ネストした表およびVARRAYのいずれについても、シングルレベル・コレクションおよびマルチレベル・コレクションで実行できます。この項では、ネストを解除する問合せの例を示します。

ネストした表は、次の例のように、TABLE構文を使用して問合せに対してネストを解除できます。

例9-4 TABLEファンクションによるネストした表のネスト解除

SELECT p.name_obj, n.num
FROM people_reltab p, TABLE(p.phones_ntab) n ;

ここで、phones_ntabは、ネストした表phones_ntabの属性を指定します。子である行(この例では電話番号)を持たない親である行も確実に取り出されるようにするには、+を使用して外部結合構文を使用します。次に例を示します。

SELECT p.name_obj, n.num
FROM people_reltab p, TABLE(p.phones_ntab) (+) n ;

問合せのSELECT構文のリストが、親表のネストした表の列以外の列を参照しない場合は、ネストした表の記憶表に対してのみ実行されるように、問合せの最適化が実行されます。

ネストを解除する問合せの構文は、VARRAYおよびネストした表のどちらの場合も同じです。たとえば、ネストした表phones_ntabではなく、phones_varという名前のVARRAYの場合を考えてみます。次の例は、TABLE構文を使用してVARRAYを問い合せます。

SELECT p.name_obj, v.num
FROM people_reltab p, TABLE(p.phones_var) v;

ネストを解除する問合せでのプロシージャおよびファンクションの使用

ネストを解除する問合せを実行するためのプロシージャおよびファンクションを作成できます。たとえば、locationがhomeである電話番号のみを戻す、home_phones()というファンクションを作成できます。home_phones()ファンクションを作成するには、次の例のようなコードを入力します。

例9-5 home_phonesファンクションの作成

CREATE OR REPLACE FUNCTION home_phones(allphones IN phone_ntabtyp)
RETURN phone_ntabtyp IS
homephones phone_ntabtyp := phone_ntabtyp();
indx1      number;
indx2      number := 0;
BEGIN
FOR indx1 IN 1..allphones.count LOOP
IF
allphones(indx1).location = 'home'
THEN
homephones.extend;    -- extend the local collection
indx2 := indx2 + 1;
homephones(indx2) := allphones(indx1);
END IF;
END LOOP;

RETURN homephones;
END;
/

ここで、人のリストおよびその自宅の電話番号を問い合せるには、次のように入力します。

例9-6 TABLEファンクションを使用した問合せのネスト解除

SELECT p.name_obj, n.num
FROM people_reltab p, TABLE(
CAST(home_phones(p.phones_ntab) AS phone_ntabtyp)) n ;

自宅の電話番号がリストされていない人も含めて、人のリストおよびその自宅の電話番号を問い合せるには、次のように入力します。

SELECT p.name_obj, n.num
FROM people_reltab p,
TABLE(CAST(home_phones(p.phones_ntab) AS phone_ntabtyp))(+) n ;

関連項目:
TABLEファンクションの詳細は、『Oracle Database SQL言語リファレンス』および『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください。

VARRAYの記憶域上の考慮点

格納されるVARRAYのサイズは、VARRAY内の現行の要素数にのみ依存し、保持できる最大要素数には関係しません。VARRAYの記憶域には、NULL情報など、わずかなオーバーヘッドがかかるため、格納されるVARRAYのサイズは、(要素のサイズ)×(要素数)より少し大きくなります。

VARRAYは、列値またはLOBとして格納されます。VARRAYの定義時に、宣言されたVARRAYのLIMIT(要素の上限値)を使用して計算されるVARRAYの最大許容サイズに基づいて、VARRAYの格納方法が決定されます。サイズが約4000バイトを超える場合、VARRAYはLOBに格納されます。その他の場合は、その列自体に列値として格納されます。さらに、インラインLOBがサポートされており、(LOBロケータ用に何バイトか予約された)大きなVARRAYの最初の4000バイトに相当する要素は、その行自体の列に格納されます。『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』も参照してください。

VARRAYのサイズ変更の伝播

VARRAY型のサイズを変更する際、依存型については新しい型バージョンが生成されます。VARRAY列がLOBとして明示的に格納されておらず、元の最大サイズが4000バイト未満の場合、このことに注意する必要があります。増加後のサイズが4000バイト以上になる場合、VARRAY列をLOBとして格納する必要があります。この場合、LOBセグメントおよびLOB索引を含めた必須LOBメタデータ情報を設定する必要があるため、VARRAY列のメタデータをアップグレードするという追加操作が必要になります。

ALTER TYPE文のCASCADEオプションを使用すると、VARRAYのサイズ変更が、依存型および依存表に伝播されます。有効な各依存型に対して新しいバージョンが生成され、前述の様々な異なる場面に基づいて、依存表メタデータが更新されます。VARRAY列がクラスタ表内に存在する場合、クラスタ表はLOBをサポートしていないため、ALTER TYPE文のCASCADEオプションの実行は失敗します。

ALTER TYPE文のCASCADEオプションでは、[NOT] INCLUDING TABLE DATAオプションも用意されています。NOT INCLUDING TABLE DATAオプションを使用すると、表のメタデータは更新されますが、データ・イメージは変換されません。VARRAYのイメージを最新バージョンの形式に変換するには、ALTER TYPE CASCADE文でINCLUDING TABLE DATAを明示的に指定するか、またはALTER TABLE UPGRADE文を発行します。

VARRAYおよびネストした表のパフォーマンス

アプリケーションでコレクション全体が1つの単位として操作される場合、VARRAYはネストした表よりも高速に処理されます。VARRAYはまとまって格納され、ネストした表とは異なり、データを取り出すための結合は必要ありません。

VARRAYの問合せ

ネストを解除する構文を、ネストした表へのアクセスの場合と同様の方法で、VARRAY列へのアクセスにも使用できます。詳細は、「ネストを解除する問合せを使用したリレーショナル形式でのオブジェクト・データの表示」を参照してください。

VARRAYの更新

VARRAYの要素単位の更新は、サポートされていません。このため、VARRAYが更新される場合、古いコレクション全体が新しいコレクションで置き換えられます。

ネストした表の設計上の考慮点

次の項では、ネストした表を使用するための設計上の考慮点について説明します。

ネストした表の記憶域

Oracleでは、ネストした表の行は別の記憶表に格納されます。システムが生成するNESTED_TABLE_ID(長さ16バイト)によって、親である行およびそれに対応する記憶表の行が関連付けられます。

図9-2に、記憶表の動作を示します。記憶表には、ネストした表列内のネストした表ごとの値が含まれています。この個々の値が、記憶表の1行に相当します。記憶表は、NESTED_TABLE_IDを使用して、個々の値に対するネストした表を追跡します。したがって、図9-2では、ネストした表Aに属するすべての値が識別され、それに続いてネストした表Bに属するすべての値も同様に識別されます。

図9-2 ネストした表の記憶域

索引構成表(IOT)に格納されたネストした表

ネストした表が主キーを持つ場合、この表をIOTとして構成できます。NESTED_TABLE_ID列が、指定された親である行に対する主キーの第一要素(プレフィックス)である場合、その子である行は物理的に1つにクラスタ化されます。このため、親である行がアクセスされるときに、そのすべての子である行を効率的に取り出せます。親である行のみがアクセスされる場合も、子である行が親である行に混入することはないため、同等の効率が維持されます。

図9-3に、ネストした表がIOTである場合の記憶表の動作を示します。記憶表では、ネストした表列内のネストした表ごとの値は、NESTED_TABLE_ID別にグループ化されます。図9-3では、記憶表のデータは、親表のNT_DATA列にあるネストした表ごとにグループ化されています。つまり、ネストした表Aのすべての値がグループ化され、ネストした表Bのすべての値も同様にグループ化され、というようにグループ化されています。

図9-3 IOT記憶域のネストした表

さらに、COMPRESS句によって、IOT列に対してプレフィックスを圧縮することが可能です。この圧縮では、それぞれの子である行にある親のキーの重複部分を取り除きます。つまり、親キーが個々の子である行で繰り返されることがないため、記憶域を大幅に節約できます。

つまり、COMPRESS句を使用してネストした表の圧縮を指定すると、同じグループの各値に対して同一のNESTED_TABLE_IDが繰り返されないため、記憶表に必要な領域容量が削減されます。かわりに、図9-4に示すように、NESTED_TABLE_IDはグループにつき1回のみ格納されます。

図9-4 IOT記憶域に圧縮して格納されたネストした表

通常は、NESTED_TABLE_ID列を主キーのプレフィックスとして使用して、ネストした表をIOTに格納することをお薦めします。さらに、IOTでプレフィックス圧縮を有効にする必要があります。ただし、通常の業務としてはネストした表を1つの単位として取り出すことがなく、子である行をクラスタ化することもない場合は、ネストした表をIOTに格納したり、圧縮を指定したりしないでください。

ネストした表の索引

(IOTでない)ヒープ表に格納されたネストした表を作成する場合、記憶表のNESTED_TABLE_ID列および親表の対応するID列に索引が自動的に作成されます。データベースでは、NESTED_TABLE_ID列を使用して、親表とネストした表の結合を実行する必要があるため、NESTED_TABLE_ID列に索引を作成することによって、ネストした表の子である行にさらに効率的にアクセスできるようになります。

ネストした表のロケータ

大規模な子集団の場合は、必要に応じて子である行にアクセスできるように、親である行、および子集団に対するロケータを戻せます。子集団のフィルタもできます。ネストした表のロケータを使用すると、各親に対して子である行が不必要に転送されることを回避できます。

次のいずれかのアクションを実行して、ネストした表のロケータを使用して子である行にアクセスできます。

- OCIコレクション関数をコールします。このアクションは、OCIColl*関数などのクライアント側コードでコレクション要素にアクセスするときに暗黙的に発生します。最初のアクセスで、コレクション全体が暗黙的に取り出されます。

関連項目:
OCIコレクション関数の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- SQLを使用して、ネストした表に対応する行を取り出します。

マルチレベル・コレクションでは、任意のネスト・レベルで指定されたコレクションを持つロケータを使用できます。

次の内容では、コレクションをロケータとして取り出すことができる方法を指定します。

- 表作成時に指定する方法

- 取出し処理中にヒントとして指定する方法

表作成時に指定する方法

コレクション型が列型として使用されていて、NESTED TABLE記憶域句が使用されている場合は、RETURN AS LOCATOR句を使用して、特定のコレクションをロケータとして取り出すように指定できます。

たとえば、inner_tableが3つのレベルのネストした表で構成されたコレクション型だとします。次の例では、RETURN AS LOCATOR句によって、常に第3レベルのネストした表がロケータとして取り出されることが指定されています。

例9-7 RETURN AS LOCATOR句の使用

CREATE TYPE inner_table AS TABLE OF NUMBER;/
CREATE TYPE middle_table AS TABLE OF inner_table;/
CREATE TYPE outer_table AS TABLE OF middle_table;/
CREATE TABLE tab1 (
col1 NUMBER,
col2 outer_table)
NESTED TABLE col2 STORE AS col2_ntab
(NESTED TABLE COLUMN_VALUE STORE AS cval1_ntab
(NESTED TABLE COLUMN_VALUE STORE AS cval2_ntab RETURN AS LOCATOR) );

取出し処理中にヒントとして指定する方法l

問合せによって、ヒントNESTED_TABLE_GET_REFSを使用してロケータとして取り出せます。次の例では、表tab1から列col2をロケータとして取り出します。

SELECT /*+ NESTED_TABLE_GET_REFS +*/ col2
FROM tab1
WHERE col1 = 2;

ただし、RETURN AS LOCATOR句の場合とは異なり、ヒントを使用する場合は、特定の内部コレクションをロケータとして戻す指定はできません。

セット・メンバーシップ問合せの最適化

ネストした表にある特定の項目を検索する場合、セット・メンバーシップ問合せが役立ちます。たとえば、次の問合せでは、homeというロケーションが、子集団のメンバーシップ、具体的には、ネストした表phones_ntab(親表people_reltabにあります)にあるかどうかをテストします。

SELECT * FROM people_reltab p
WHERE 'home' IN (SELECT location FROM TABLE(p.phones_ntab)) ;

Oracleでは、子集団のメンバーシップを内部的にセミ結合に変換することによって、そのメンバーシップをテストする問合せをより効率的に実行しています。ただし、この最適化は、ALWAYS_SEMI_JOIN初期化パラメータが設定されている場合にのみ実行されます。セミ結合を実行する場合、このパラメータの有効な値はMERGEおよびHASHです。これらのパラメータ値によって、使用すべき結合メソッドが示されます。

注意:
前述の例では、homeおよびlocationは子集団要素です。子集団要素がオブジェクト型である場合は、セット・メンバーシップ問合せを実行するマップ・メソッドまたはオーダー・メソッドが必要です。

マルチレベル・コレクションの設計上の考慮点

第5章「コレクション・データ型のサポート」では、コレクション型をネストして、真のマルチレベル・コレクション(たとえばネストした表のネストした表、VARRAYのネストした表、ネストした表のVARRAY、コレクション型の属性を持つオブジェクト型のVARRAYまたはネストした表など)を作成する方法について説明しています。

REFを使用して間接的にコレクションをネストすることもできます。たとえば、ネストした表属性またはVARRAYの属性を持つオブジェクトを参照する属性を持つオブジェクト型のネストした表を作成できます。実際にはマルチレベル・コレクションのすべての要素にアクセスする必要はない、という場合、ロードする必要があるのは、要素そのものではなくREFのみなので、REFを使用してコレクションをネストすると、パフォーマンスが向上する可能性があります。

真のマルチレベル・コレクション(具体的にはマルチレベルのネストした表)を使用すると、コレクションの個々の要素にアクセスする問合せのパフォーマンスが向上します。すべての要素にアクセスする必要はない場合、ネストした表ロケータを使用すると、プログラムで規定されたアクセスのパフォーマンスが向上する可能性があります。

REFを使用して別のコレクションをネストする例として、例9-1に示したname_objtyp、address_objtypおよびphone_ntabtypの各オブジェクト型を使用して、person_objtypと呼ばれる新しいオブジェクト型を作成するとします。1人が複数の電話番号を持つことがあるため、phone_ntabtypオブジェクト型がネストした表になっていることに注意してください。

person_objtypオブジェクト型およびpeople_objtabオブジェクト型のpeople_objtabというオブジェクト表を作成するには、次のSQL文を発行します。

例9-8 マルチレベル・コレクションを含むオブジェクト表の作成

CREATE TYPE person_objtyp AS OBJECT (
id            NUMBER(4),
name_obj      name_objtyp,
address_obj   address_objtyp,
phones_ntab   phone_ntabtyp);
/

CREATE TABLE people_objtab OF person_objtyp (id PRIMARY KEY)
NESTED TABLE phones_ntab STORE AS phones_store_ntab ;

people_objtab表は、people_reltab表と同じ属性を持ちます。違いは、people_objtabは行オブジェクトを持つオブジェクト表であり、people_reltab表は列オブジェクトを持つリレーショナル表であるという点です。

関連項目:
「リレーショナル表の列オブジェクトの記憶域」

図9-5 people_objtabオブジェクト表のオブジェクト・リレーショナル表現

ここで、people_objtabオブジェクト表にある行オブジェクトを他の表から参照できます。たとえば、次の項目が含まれるprojects_objtab表を作成するとします。

- 各プロジェクトのプロジェクト識別番号

- 各プロジェクトのタイトル

- 各プロジェクトのプロジェクト・リード

- 各プロジェクトの説明

- 各プロジェクトに割り当てられたチームのメンバーを格納するネストした表コレクション

プロジェクト・リードに対してはpeople_objtabにREFを使用でき、チームに対してはREFのネストした表コレクションを使用できます。まず、person_objtypオブジェクト型に基づいて、personref_ntabtypというネストした表オブジェクト型を作成します。

CREATE TYPE personref_ntabtyp AS TABLE OF REF person_objtyp;
/

これで、オブジェクト表projects_objtabを作成する準備ができました。例9-9に示すように、まずオブジェクト型projects_objtypを作成してから、projects_objtypに基づいてオブジェクト表projects_objtabを作成します。

例9-9 REFを使用したオブジェクト表の作成

CREATE TYPE projects_objtyp AS OBJECT (
id              NUMBER(4),
title           VARCHAR2(15),
projlead_ref    REF person_objtyp,
description     CLOB,
team_ntab       personref_ntabtyp);
/
CREATE TABLE projects_objtab OF projects_objtyp (id PRIMARY KEY)
NESTED TABLE team_ntab STORE AS team_store_ntab ;

図9-6 projects_objtabオブジェクト表のオブジェクト・リレーショナル表現

people_objtabオブジェクト表およびprojects_objtabオブジェクト表が作成されると、間接的にネストしたコレクションを持つことになります。つまり、projects_objtab表には、people_objtab表にある人物を指すREFのネストした表コレクションが含まれ、people_objtab表にある人物には電話番号のネストした表コレクションがあります。

例9-10のように、people_objtab表に値を挿入できます。

例9-10 people_objtabオブジェクト表への値の挿入

INSERT INTO people_objtab VALUES (
0001,
name_objtyp('JOHN', 'JACOB', 'SCHMIDT'),
address_objtyp('1252 Maple Road', 'Fairfax', 'VA', '22033'),
phone_ntabtyp(
phone_objtyp('home', '650.555.0141'),
phone_objtyp('work', '510.555.0122'))) ;

INSERT INTO people_objtab VALUES (
0002,
name_objtyp('MARY', 'ELLEN', 'MILLER'),
address_objtyp('33 Spruce Street', 'McKees Rocks', 'PA', '15136'),
phone_ntabtyp(
phone_objtyp('home', '415.555.0143'),
phone_objtyp('work', '650.555.0192'))) ;

INSERT INTO people_objtab VALUES (
0003,
name_objtyp('SARAH', 'MARIE', 'SINGER'),
address_objtyp('525 Pine Avenue', 'San Mateo', 'CA', '94403'),
phone_ntabtyp(
phone_objtyp('home', '510.555.0101'),
phone_objtyp('work', '650.555.0178'),
phone_objtyp('cell', '650.555.0143'))) ;

さらに、例9-11のように、REF演算子を使用してpeople_objtabオブジェクト表から選択することによって、projects_objtabリレーショナル表に挿入できます。

例9-11 projects_objtabオブジェクト表への値の挿入

INSERT INTO projects_objtab VALUES (
1101,
'Demo Product',
(SELECT REF(p) FROM people_objtab p WHERE id = 0001),
'Demo the product, show all the great features.',
personref_ntabtyp(
(SELECT REF(p) FROM people_objtab p WHERE id = 0001),
(SELECT REF(p) FROM people_objtab p WHERE id = 0002),
(SELECT REF(p) FROM people_objtab p WHERE id = 0003))) ;

INSERT INTO projects_objtab VALUES (
1102,
'Create PRODDB',
(SELECT REF(p) FROM people_objtab p WHERE id = 0002),
'Create a database of our products.',
personref_ntabtyp(
(SELECT REF(p) FROM people_objtab p WHERE id = 0002),
(SELECT REF(p) FROM people_objtab p WHERE id = 0003))) ;

注意:
この例では、REFを格納するためにネストした表を使用していますが、REFをVARRAYに格納することもできます。つまり、REFのVARRAYを作成できます。

メソッドの設計上の考慮点

この項では、メソッドを使用した作業での考慮点を説明します。

- メソッド・ファンクションに対する言語の選択

- 静的メソッド

- メンバー・プロシージャでのSELF IN OUT NOCOPYの使用

- タイプ・メソッドの戻り値に基づくファンクション索引

メソッド・ファンクションに対する言語の選択

メソッド・ファンクションは、Oracleでサポートされる任意の言語(PL/SQL、Java、Cなど)で実装できます。特定のアプリケーション用に言語を選択する場合は、次の要因を考慮してください。

- 使用しやすさ

- SQLコール

- 実行速度

- 同一/異なるアドレス空間

一般に、アプリケーションで主に計算を実行する場合には、Cが適していますが、比較的多くのデータベース・コールを実行する場合は、PL/SQLまたはJavaが適しています。

Cで実装されるメソッドは、外部プロシージャを使用して、サーバーとは別のプロセスで実行されます。それに対して、JavaまたはPL/SQLで実装されるメソッドは、サーバーと同じプロセスで実行されます。

メソッドの実装例

この項で説明する例では、異なる言語で実装されたメソッドを持つオブジェクト型が関係しています。この例では、オブジェクト型ImageTypeは、ID属性(一意に識別されるNUMBER)およびIMG属性(イメージを格納するBLOB)を持ちます。オブジェクト型ImageTypeは、次のメソッドを持ちます。

- get_nameメソッド。データベース内でイメージの名前を検索してフェッチします。このメソッドは、PL/SQLで実装されています。

- rotateメソッド。イメージを回転します。このメソッドは、Cで実装されています。

- clearメソッド。指定された色の新しいイメージを戻します。このメソッドは、Javaで実装されています。

Cでメソッドを実装する場合は、外部Cルーチンが含まれるライブラリを指す、LIBRARYオブジェクトを定義する必要があります。Javaでメソッドを実装する場合を想定して、この例では、メソッドを持つJavaクラスがコンパイルされ、Oracleにアップロードされていると仮定しています。

例9-12に、オブジェクト型の定義およびそのメソッドを示します。

例9-12 様々な言語で実装されたメソッドを持つオブジェクト型の作成

CREATE LIBRARY myCfuncs TRUSTED AS STATIC
/

CREATE TYPE ImageType AS OBJECT (
id   NUMBER,
img  BLOB,
MEMBER FUNCTION get_name return VARCHAR2,
MEMBER FUNCTION rotate return BLOB,
STATIC FUNCTION clear(color NUMBER) return BLOB);/

CREATE TYPE BODY ImageType AS
MEMBER FUNCTION get_name RETURN VARCHAR2
IS
imgname  VARCHAR2(100);
sqlstmt VARCHAR2(200);
BEGIN
sqlstmt := 'SELECT name INTO imgname FROM imgtab WHERE imgid = id';
EXECUTE IMMEDIATE sqlstmt;
RETURN imgname;
END;

MEMBER FUNCTION rotate RETURN BLOB
AS LANGUAGE C
NAME "Crotate"
LIBRARY myCfuncs;

STATIC FUNCTION clear(color NUMBER) RETURN BLOB
AS LANGUAGE JAVA
NAME 'myJavaClass.clear(oracle.sql.NUMBER) return oracle.sql.BLOB';

END;
/

制限事項:
タイプ・メソッドは、Javaの静的メソッドのみにマップできます。

関連項目:

- 詳細は、『Oracle Database Java開発者ガイド』を参照してください。

- 言語の選択の詳細は、第4章「Oracleプログラム環境のオブジェクト・サポート」を参照してください。

静的メソッド

静的メソッドは、SELF値が第1パラメータとして渡されない点で、メンバー・メソッドと異なります。SELFの値が問題ではないメソッドは、静的メソッドとして実装する必要があります。静的メソッドは、ユーザー定義コンストラクタに使用できます。

例9-13では、コンストラクタに類似したメソッドで、明示的な入力パラメータに基づいてその型のインスタンスを作成し、指定された表にそのインスタンスを挿入します。

例9-13 静的メソッドを持つオブジェクト型の作成

CREATE TYPE atype AS OBJECT(
a1 NUMBER,
STATIC PROCEDURE newa (
p1        NUMBER,
tabname   VARCHAR2,
schname   VARCHAR2));
/
CREATE TYPE BODY atype AS
STATIC PROCEDURE newa (p1 NUMBER, tabname VARCHAR2, schname VARCHAR2)
IS
sqlstmt VARCHAR2(100);
BEGIN
sqlstmt := 'INSERT INTO '||schname||'.'||tabname|| ' VALUES (atype(:1))';
EXECUTE IMMEDIATE sqlstmt USING p1;
END;
END;
/

CREATE TABLE atab OF atype;

BEGIN
atype.newa(1, 'atab', 'HR');
END;
/

メンバー・プロシージャでのSELF IN OUT NOCOPYの使用

メンバー・プロシージャにSELFが宣言されていない場合、そのパラメータ・モードはデフォルトでIN OUTに設定されます。ただし、デフォルトの動作には、NOCOPYコンパイラ・ヒントは含まれません。「メンバー・メソッド」を参照してください。

IN OUT実パラメータの値が対応する仮パラメータにコピーされるため、パラメータがラージ・オブジェクト型のインスタンスなどの大きなデータ構造を保持している場合、コピーによって実行速度が遅くなります。

パフォーマンスを改善するために、パラメータとしてラージ・オブジェクト型を渡す場合、SELF IN OUT NOCOPYを含められます。次に例を示します。

MEMBER PROCEDURE my_proc (SELF IN OUT NOCOPY my_LOB)

関連項目:

- NOCOPYを使用した場合のパフォーマンスの問題および使用上の制限事項は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- CREATE PROCEDURE文でのNOCOPYの使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

タイプ・メソッドの戻り値に基づくファンクション索引

ファンクション索引は、式またはファンクションの戻り値に基づいた索引です。このファンクションは、オブジェクト型のメソッド・ファンクションの場合もあります。

メソッド・ファンクションに基づくファンクション索引は、索引付けの対象となっている列または表の各オブジェクト・インスタンスに対するファンクションの戻り値をあらかじめ計算しておいて、それらの値を索引に格納します。この索引では、ファンクションを評価しなおすことなく列や表が参照されます。

ファンクション索引は、WHERE句にファンクションを含む問合せのパフォーマンスを向上させる場合に役立ちます。たとえば、次のコードにはオブジェクト表empsの問合せが含まれています。

CREATE TYPE emp_t AS OBJECT(
name   VARCHAR2(36),
salary NUMBER,
MEMBER FUNCTION bonus RETURN NUMBER DETERMINISTIC);
/
CREATE TYPE BODY emp_t IS
MEMBER FUNCTION bonus RETURN NUMBER DETERMINISTIC IS
BEGIN
RETURN self.salary * .1;
END;
END;
/

CREATE TABLE emps OF emp_t ;

SELECT e.name
FROM emps e
WHERE e.bonus() > 2000;

この問合せを評価するためには、この表の各行オブジェクトに対するbonus()を評価する必要があります。bonus()の戻り値に対してファンクション索引がある場合は、この評価の作業はすでに実行済なので、Oracleの動作としては、索引内にある問合せ結果を検索するのみですみます。これによって、Oracleが問合せを実行した結果を戻す速度が向上します。

ファンクションの戻り値の索引付けが効果的に実行できるのは、戻り値が一定である場合、つまり、ファンクションが各オブジェクト・インスタンスに対して常に同じ値を戻す場合のみです。このため、ファンクション索引でユーザー定義ファンクションを使用する場合は、前述の例のように、DETERMINISTICキーワードを使用してそのファンクションを宣言しておく必要があります。このキーワードによって、各オブジェクト・インスタンスの入力引数値の集合に対して、このファンクションから常に一定の値が戻されることが保証されます。

次の例では、表empsのメソッドbonus()に対するファンクション索引を作成します。

例9-14 メソッドに対するファンクション索引の作成

CREATE INDEX emps_bonus_idx ON emps x (x.bonus()) ;

関連項目:
ファンクション索引の詳細は、『Oracle Database概要』および『Oracle Database SQL言語リファレンス』を参照してください。

実行者権限を使用した再利用コードの作成

任意のスキーマで使用できる汎用オブジェクト型を作成するには、CREATE OR REPLACE TYPEのAUTHID CURRENT_USERオプションを介して、実行者権限を使用する型を定義する必要があります。一般に、次の条件がいずれも真である場合に実行者権限を使用します。

- データにアクセスし操作するタイプ・メソッドがある。

- これらのタイプ・メソッドを定義していないユーザーによって使用される必要がある。

たとえば、HRによって「静的メソッド」で作成されたatype型に対する実行権限を、ユーザーOEに付与し、その後この型に基づいて表atabを作成できます。

GRANT EXECUTE ON atype TO oe;
CONNECT oe;
Enter password: password
CREATE TABLE atab OF HR.atype ;

ここで、ユーザーOEが、次の文でatypeを使用するとします。

BEGIN -- follwing call raises an error, insufficient privileges
HR.atype.newa(1, 'atab', 'OE');
END;
/

型定義者(HR)には、newaプロシージャで挿入を実行するために必要な権限がないため、この文を実行するとエラーが戻されます。このエラーは、実行者権限を使用してatypeを定義することによって回避できます。ここで、まず両方のスキーマのatab表を削除し、実行者権限を使用してatypeを再作成します。

DROP TABLE atab;
CONNECT hr;
Enter password: password
DROP TABLE atab;
DROP TYPE atype FORCE;
COMMIT;

CREATE TYPE atype AUTHID CURRENT_USER AS OBJECT(
a1 NUMBER,
STATIC PROCEDURE newa(p1 NUMBER, tabname VARCHAR2, schname VARCHAR2));
/
CREATE TYPE BODY atype AS
STATIC PROCEDURE newa(p1 NUMBER, tabname VARCHAR2, schname VARCHAR2)
IS
sqlstmt VARCHAR2(100);
BEGIN
sqlstmt := 'INSERT INTO '||schname||'.'||tabname|| '
VALUES (HR.atype(:1))';
EXECUTE IMMEDIATE sqlstmt USING p1;
END;
END;
/

これで、ユーザーOEが再度atypeを使用しようとした場合、文は正常に実行されます。

GRANT EXECUTE ON atype TO oe;
CONNECT oe;
Enter password: password
CREATE TABLE atab OF HR.atype;

BEGIN
HR.atype.newa(1, 'atab', 'OE');
END;
/
DROP TABLE atab;
CONNECT hr;
Enter password: password
DROP TYPE atype FORCE;

このとき文が正常に実行されるのは、プロシージャは定義者(HR)権限でなく実行者(OE)権限で実行されるためです。

型階層内では、サブタイプには、そのすぐ上のスーパータイプと同じ権限モデルが存在します。つまり、サブタイプはスーパータイプの権限を暗黙的に継承するため、明示的な権限の指定はできません。さらに、スーパータイプが定義者権限によって宣言された場合は、サブタイプはスーパータイプと同じスキーマ内に配置されている必要があります。これらの規則によって、実行者権限型の階層がスキーマを超えて展開されることになります。ただし、定義者権限モデルを使用する型の階層は、単一のスキーマ内に存在する必要があります。次に例を示します。

CREATE TYPE deftype1 AS OBJECT (...); --Definer-rights type
CREATE TYPE subtype1 UNDER deftype1 (...); --subtype in same schema as supertype
CREATE TYPE schema2.subtype2 UNDER deftype1 (...); --ERROR
CREATE TYPE invtype1 AUTHID CURRENT_USER AS OBJECT (...); --Invoker-rights type
CREATE TYPE schema2.subtype2 UNDER invtype1 (...); --LEGAL

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

サブプログラムでのロールの使用は、定義者権限で実行するか、実行者権限で実行するかによって異なります。定義者権限のサブプログラム内では、ロールはすべて無効です。ロールは権限チェックに使用されないため、設定できません。

実行者権限のサブプログラム内では、ロールは有効です(サブプログラムが直接または間接的に、定義者権限サブプログラムにコールされた場合は無効です)。ロールは権限チェックに使用され、固有の動的SQLを使用してセッションに設定できます。ただし、ロールはコンパイル時ではなく実行時に適用されるため、ロールを使用してテンプレート・オブジェクトに権限を付与することはできません。

オブジェクト表およびオブジェクト列のレプリケーション

オブジェクト表およびオブジェクト・ビューは、マテリアライズド・ビューとしてレプリケートできます。また、あるオブジェクト型、コレクション型またはREF型の列を含むリレーショナル表もレプリケートできます。このようなマテリアライズド・ビューは、オブジェクト・リレーショナル・マテリアライズド・ビューと呼ばれます。

オブジェクト・リレーショナル・マテリアライズト・ビューが必要とするすべてのユーザー定義型は、マスター・サイトおよびマテリアライズド・ビュー・サイトに存在する必要があります。そのようなユーザー定義型のIDおよびバージョンは両方のサイトで一致している必要があります。

この項の内容は次のとおりです。

- オブジェクト型、コレクション型またはREF型の列のレプリケーション

- オブジェクト表のレプリケーション

オブジェクト型、コレクション型またはREF型の列のレプリケーション

更新可能とするには、オブジェクト列を含む表に基づくマテリアライズド・ビューでは、そのビューを定義する問合せにある列をオブジェクトとして選択する必要があります。問合せが、その列のオブジェクト型の一定の属性のみを選択する場合は、マテリアライズド・ビューは読取り専用となります。

ビュー定義問合せは、コレクション型またはREF型の列も選択できます。REFは、主キー・ベースのキーか、システム生成のキーのいずれかで、有効範囲付きまたは有効範囲なしの場合があります。有効範囲付きREFの列は、元のリモート表ではなくマテリアライズド・ビュー・サイトの別の表(たとえば、マスター表のローカル・マテリアライズド・ビューなど)に、有効範囲を付けなおすことができます。

オブジェクト表のレプリケーション

オブジェクト表に基づくマテリアライズド・ビューはオブジェクト・マテリアライズド・ビューと呼ばれます。このようなマテリアライズド・ビューは、それ自体がオブジェクト表です。オブジェクト・マテリアライズド・ビューは、OF typeのキーワードをCREATE MATERIALIZED VIEW文に追加することによって作成されます。次に例を示します。

CREATE MATERIALIZED VIEW customer OF cust_objtyp AS
SELECT * FROM HR.Customer_objtab@dbs1;

通常のオブジェクト表の場合と同様、オブジェクト・マテリアライズド・ビューの各行もオブジェクト・インスタンスです。したがって、マテリアライズド・ビューを作成するビュー定義問合せは、マスター表にあるオブジェクト全体を選択する必要があります。この問合せは、オブジェクト型属性のサブセットのみの選択はできません。たとえば、次のようなマテリアライズド・ビューは使用できません。

CREATE MATERIALIZED VIEW customer OF cust_objtyp AS
SELECT * FROM HR.Customer_objtab@dbs1;

OF typeのキーワードを省略することによってオブジェクト表からオブジェクト・リレーショナル・マテリアライズド・ビューを作成できますが、そのようなビューは読取り専用です。オブジェクト表から、更新可能なオブジェクト・リレーショナル・マテリアライズド・ビューを作成できます。

たとえば、次のCREATE MATERIALIZED VIEW文は、オブジェクト表の読取り専用オブジェクト・リレーショナル・マテリアライズド・ビューを作成します。ビュー定義問合せは、そのオブジェクト型のすべての列および属性を選択しますが、オブジェクトの属性として選択するわけではないので、作成されたビューは、オブジェクト・リレーショナル・ビューで、読取り専用です。

CREATE MATERIALIZED VIEW customer AS
SELECT * FROM HR.Customer_objtab@dbs1;

オブジェクト表に基づいたオブジェクト・リレーショナル・ビューとマテリアライズド・ビューのいずれの場合も、マスターのオブジェクト表の型がFINALでない場合は、マテリアライズド・ビューの定義問合せにあるFROM句に、ONLYキーワードが含まれている必要があります。次に例を示します。

CREATE MATERIALIZED VIEW customer OF cust_objtyp AS
SELECT CustNo FROM ONLY HR.Customer_objtab@dbs1;

そうでない場合は、FROM句からONLYキーワードを省略してください。

関連項目:
オブジェクト表とオブジェクト列のレプリケーションの詳細は、『Oracle Databaseアドバンスト・レプリケーション』を参照してください。

オブジェクトに対する制約

Oracleでは、型指定内での制約およびデフォルトはサポートされません。ただし、表を作成するときに、制約およびデフォルトを指定できます。

例9-15 表作成時のオブジェクト型に対する制約の指定

CREATE TYPE customer_typ AS OBJECT(
cust_id INTEGER);
/
CREATE TYPE department_typ AS OBJECT(
deptno INTEGER);
/
CREATE TABLE customer_tab OF customer_typ (
cust_id default 1 NOT NULL);

CREATE TABLE department_tab OF department_typ (
deptno PRIMARY KEY);

CREATE TABLE customer_tab1 (
cust customer_typ DEFAULT customer_typ(1)
CHECK (cust.cust_id IS NOT NULL),
some_other_column VARCHAR2(32));

型進化に関する考慮点

次の項では、型進化に関連する設計上の考慮点について説明します。

この項の内容は次のとおりです。

- 型の変更のクライアントへの送信

- デフォルトのコンストラクタの変更

- 型のFINALプロパティの変更

型の変更のクライアントへの送信

ある型がサーバー側で進化すると、この型を使用するすべてのクライアント・アプリケーションで、この型に対応付けられている構造体の変更が必要になります。この変更は、OTTまたはJPublisherを使用して実行できます。また、構造体の変更に伴ってプログラムの変更が必要な場合もあります。このような変更を行った後、アプリケーションをコンパイルしなおし、再リンクする必要があります。

サード・パーティ・アプリケーションのリリース間で型が変更される場合があります。サード・パーティ・アプリケーションの最新リリースとの互換性を確立するために再コンパイルする必要があることをクライアント・アプリケーションに通知するには、リリース指向互換性初期化ファンクションをクライアントからコールします。このファンクションは、クライアント・アプリケーションのどのリリースを使用しているかを示す文字列を入力として受け取ることができます。リリース文字列が最新バージョンと一致しない場合は、エラーが発生します。その場合、クライアント・アプリケーションは、最新リリースとの互換性を確立するための変更の一環として、リリース文字列を変更します。

次に例を示します。

FUNCTION compatibility_init(
rel IN VARCHAR2, errmsg OUT VARCHAR2)
RETURN NUMBER;

ここで

- relは、その製品、たとえば、リリース10.1によって選択されたリリース文字列です。

- errmsgは、戻す必要のある任意のエラー・メッセージです。

- このファンクションは、成功すると0(ゼロ)を戻し、エラーの場合は0(ゼロ)以外の値を戻します。

デフォルトのコンストラクタの変更

型が変更されると、新しく追加された属性をパラメータ・リストに含めるためなどに、デフォルトでシステム定義されたコンストラクタを変更する必要があります。デフォルトのコンストラクタを使用している場合は、コールをコンパイルするためにプログラム内の起動を変更する必要があります。

システム定義されたデフォルトのコンストラクタではなく、独自でコンストラクタ・ファンクションを定義して使用する場合は、コンストラクタのコールを変更する必要はありません。「ユーザー定義コンストラクタの利点」を参照してください。

型のFINALプロパティの変更

型T1を、FINALからNOT FINALに変更した場合、クライアント・プログラムにある型T1の属性はすべて、インライン構造体からT1へのポインタに変更されます。したがって、この属性がアクセスされた場合に参照解除を使用できるようにするには、プログラムを変更する必要があります。

逆に、ある型を、NOT FINALからFINALに変更するには、その型の属性をポインタからインライン構造体に変更する必要があります。

たとえば、型T1(a int)とT2(b T1)があるとします(ここで、T1のプロパティはFINALです)。T2に対応するC/JAVA構造体はT2(T1 b)です。ところが、T1のプロパティをNOT FINALに変更すると、T2の構造体はT2(T1 *b)になります。

Oracleオブジェクトでのパラレル問合せ

Oracleでは、オブジェクト、およびビューから合成されたオブジェクトを使用して、パラレル問合せを実行できます。ただし、次の制限があります。

- (ORDER BY、GROUP BYおよびSET操作を使用して)結合およびソートをパラレルに実行する問合せを行うには、MAPファンクションが必要です。MAPファンクションがない場合、問合せは自動的にシリアルになります。

- ネストした表でのパラレル問合せはサポートされません。表に対するパラレル・ヒントまたはパラレル属性がある場合でも、問合せはシリアルになります。

- パラレルDMLおよびパラレルDDLは、オブジェクトではサポートされません。DMLおよびDDLは、常にシリアルに実行されます。

- パラレルDMLは、INSTEAD OFトリガーを持つビューではサポートされません。ただし、トリガー内の個々の文は、パラレル化できます。

設計上の考慮点のヒントおよび技法

次の項では、Oracleのオブジェクト型を使用した作業の様々な側面に関するヒントを示します。

この項の内容は次のとおりです。

- 型進化かサブタイプの作成かの決定

- ANYDATAとユーザー定義型の相違点

- ポリモフィック・ビュー: オブジェクト・ビュー階層の代入

- SQLJオブジェクト型

- その他の設計ヒント

型進化かサブタイプの作成かの決定

アプリケーションがライフ・サイクルを終了するまでには、既存のオブジェクト型を変更するか、それとも、新しい要件を満たす特化されたサブタイプを作成するか、という問題が頻繁に発生します。その答えは、新しい要件の性質およびアプリケーションのセマンティクス全体でのコンテキストによって異なります。次に2つの例をあげて説明します。

広範囲に使用されているベース型の変更

属性Street、State、ZIPを持つオブジェクト型addressがあるとします。

CREATE TYPE address AS OBJECT (
Street  VARCHAR2(80),
State   VARCHAR2(20),
ZIP     VARCHAR2(10));
/

後になって、世界各地の住所をサポートするためには、Country属性を追加してaddress型を拡張する必要性に気がつきます。addressのサブタイプの作成とaddress型自体の進化とでは、どちらが得策でしょうか。

アプリケーション全体にわたって広範囲に使用されている一般的なベース型の場合は、型進化を通じて変更を実行することをお薦めします。

特化の追加

図形型(たとえば、曲線、円、正方形、テキスト)の既存の型階層に、追加のバリエーション、具体的にはベジエ曲線を格納する必要があるとします。ベース型の不足を反映しないこのような新しい特化をサポートするために、継承を使用して、Curve型の下に、新しいサブタイプBezierCurveを作成する必要があります。

つまり、必要とされる変更のセマンティクスによって、型進化を使用すべきか、それとも継承を使用すべきかが決まります。より全般的な変更で、ベース型に影響が及ぶ場合は、型進化を使用してください。より特化された変更に対しては、継承を使用して変更を実行してください。

ANYDATAとユーザー定義型の相違点

ANYDATAはOracleによって提供される型で、任意のOracleデータ型のインスタンスを、組込み型かユーザー定義かにかかわらず保持できます。ANYDATAは自己記述的な型で、インスタンスの形式を決定するために使用できるリフレクションに類似したAPIです。

代入性機能を通して、継承およびANYDATAは、ともにプレースホルダ内に考えられるインスタンスの任意の集合を格納するポリモフィックな能力を備えていますが、この2つのモデルがその機能を提供する形式は異なります。

継承モデルの場合は、考えられるインスタンスのポリモフィックな集合は、単一の型の階層の一構成部分である必要があります。変数には、定義された型またはそのサブタイプのインスタンスのみを保持する潜在的な能力があります。スーパータイプの属性にアクセスして、そのサブタイプで定義されている(またサブタイプによってオーバーライドされる可能性のある)メソッドをコールできます。IS OF演算子およびTREAT演算子を使用して、あるインスタンスの具体的な型をテストすることもできます。

ただし、ANYDATA変数は、異質なインスタンスを格納する可能性があります。インスタンスを抽出してしまわないかぎり、ANYDATA変数に格納されている実際のインスタンスの属性にアクセスすることも、メソッドをコールすることもできません。該当するインスタンスの型を抽出するには、ANYDATAメソッドを使用します。ANYDATAは、ファンクション/プロシージャがパラメータの具体的な型には関心がない場合にパラメータの受渡しを行う場合に便利です。

継承は優れたモデリング、厳密な型指定、特化などを提供します。共通するものがあるとはかぎらない、任意の数の考えられるインスタンスのうちの1つを保持するのみの場合は、ANYDATAを使用してください。

ポリモフィック・ビュー: オブジェクト・ビュー階層の代入

第6章「オブジェクト・モデルのリレーショナル・データへの適用」では、それぞれが単一の型のオブジェクトを含んでいるオブジェクト・ビューの集合からビュー階層を構築する方法について説明しました。このようなビュー階層では、その階層内のビューに対する問合せによる、ビューまたはそのサブビューによって格納されたオブジェクトのポリモフィックな集合の参照が可能です。

このようなポリモフィックな問合せをサポートする代入の方法として、オブジェクトのポリモフィックな集合を戻す問合せに基づいてオブジェクト・ビューを定義できます。このアプローチは、あるビューを既存の表またはビューの集合にまたがって定義するときに特に便利です。

たとえば、Person_tのオブジェクト・ビューを、Employee_tインスタンスも含めたPerson_tインスタンスを戻す問合せに対して定義できます。次の文からは、persons表から個人を、employees表から従業員を選択する問合せに基づいてビューが作成されます。

CREATE VIEW Persons_view OF Person_t AS
SELECT Person_t(...) FROM persons
UNION ALL
SELECT TREAT(Employee_t(...) AS Person_t) FROM employees;

このビューに対して定義されているINSTEAD OFトリガーのかわりに、VALUEファンクションを使用して、現在のオブジェクトにアクセスでき、また、オブジェクトの最も具体的な型に基づいて適切なアクションをとることができます。

ポリモフィック・ビューとオブジェクト・ビュー階層には、次のような重要な相違点があります。

- アドレス指定可能度: ビュー階層では、各サブビューは、問合せおよびDML文の中で別々に参照できます。したがって、特定の型のオブジェクトの各集合には、論理名があります。一方、ポリモフィック・ビューは単一のビューなので、特定の型のオブジェクトの集合を取得するには、述語を使用する必要があります。

- 進化: 新しいサブタイプを追加する場合は、既存のビュー定義を変更することなくビュー階層にサブビューを追加できます。ポリモフィック・ビューの場合は、別のUNIONブランチを追加することによって、単一のビュー定義を変更する必要があります。

- DML文: ビュー階層では、各サブビューは、本質的に更新可能であるか、INSTEAD OFトリガーを持っているかのいずれかです。ポリモフィック・ビューの場合は、ビュー上の与えられた操作に対してINSTEAD OFトリガーを1つのみ定義できます。

SQLJオブジェクト型

この項では、SQLJオブジェクト型について説明します。

SQLJオブジェクト型の使用目的

『Information Technology - SQLJ - Part 2』ドキュメント(SQLJ規格)によると、SQLJオブジェクト型は、Java用に設計されたデータベース・オブジェクト型です。SQLJオブジェクト型はJavaクラスにマップされます。マッピングが拡張SQLのCREATE TYPEコマンド(DDL文)によって登録されると、JavaアプリケーションでOracle JDBCドライバを通じて、Javaオブジェクトを直接またはデータベースから、挿入または選択できるようになります。したがって、ユーザーは、同じクラスを、クライアントではJDBCを使用して、サーバーではSQLメソッドのディスパッチによって、デプロイできます。

SQLJオブジェクト型作成時に実行されるアクション

拡張SQLのCREATE TYPEコマンドは、次のことを行います。

- データベース・カタログに属性、ファンクションおよびJavaクラスの外部名を移入します。また、Javaクラスとそれに対応するSQLJオブジェクト型間の依存関係は維持されます。

- Javaクラスが存在することを検証し、また、それによってUSING句の値に対応するインタフェースが実装されることも検証します。

- Javaフィールドが(EXTERNAL NAME句で指定されているとおりに)存在すること、また、これらのフィールドが対応するSQL属性に対する互換性を検証します。

- コンストラクタ、外部変数名、結果としてselfを返す外部ファンクションをサポートする内部クラスを生成します。

SQLJオブジェクト型の用途

SQLJオブジェクト型は、SQLオブジェクト型の特殊なケースで、すべてのメソッドがJavaクラスで実装されています。Javaクラスと対応するSQL型間のマッピングは、SQLJオブジェクト型仕様によって管理されます。つまり、SQLJオブジェクト型仕様には、対応する型本体の仕様はありません。

また、SQLJオブジェクト型間の継承ルールによって、Javaクラス階層と対応するSQLJオブジェクト型階層の正しいマッピングが指定されます。これらのルールによって、SQLJ型階層に有効なマッピングが含まれていることが保証されます。したがって、SQLJオブジェクト型のスーパータイプまたはサブタイプは別のSQLJオブジェクト型である必要があります。

カスタム・オブジェクト型の用途

カスタム・オブジェクト型は、SQLオブジェクト型にアクセスするためのJavaインタフェースです。SQLオブジェクト型には、PL/SQL、Java、Cなどの言語で実装されたメソッドが含まれている場合があります。与えられたSQLオブジェクト型内のJavaで実装されたメソッドは、関連のない様々なクラスに属することができます。つまり、SQLオブジェクト型は特定のJavaクラスにマップされるわけではありません。

クライアントがこれらのオブジェクトにアクセスできるようにするため、JPublisherを使用して対応するJavaクラスを生成できます。さらに、ユーザーは、生成されたクラスを、対応するメソッドのコードで補強する必要があります。別の方法として、SQLオブジェクト型に対応するクラスを作成する方法もあります。

JDBCユーザーは、マップ内のSQL型名とそれに対応するJavaクラス間の対応関係を実行時に登録する必要があります。

SQLJオブジェクト型とJDBCを使用したカスタム・オブジェクト型の相違点

次の表は、SQLJオブジェクト型とカスタム・オブジェクト型の相違点の要約です。

表9-1 SQLJオブジェクト型とカスタム・オブジェクト型の相違点

特性

SQLJオブジェクト型の動作

カスタム・オブジェクト型の動作

型コード

OracleTypes.JAVA_STRUCT型コードを使用して、SQLJオブジェクト型をSQLのOUTパラメータとして登録します。OracleTypes.JAVA_STRUCT型コードは、ORADataインタフェースまたはSQLDataインタフェースを実装しているクラスの_SQL_TYPECODEフィールドでも使用されます。

OracleTypes.STRUCT型コードを使用して、カスタム・オブジェクト型をSQLのOUTパラメータとして登録します。OracleTypes.STRUCT型コードは、ORADataインタフェースまたはSQLDataインタフェースを実装しているクラスの_SQL_TYPECODEフィールドでも使用されます。

作成

まず、SQLDataまたはORADataインタフェースおよびORADataFactoryインタフェースを実装するJavaクラスを作成してから、Javaクラスをデータベースにロードします。次に、SQLJオブジェクト型に対して拡張SQLのCREATE TYPEコマンドを発行します。

カスタム・オブジェクト型に対して拡張SQLのCREATE TYPEコマンドを発行してから、JPublisherを使用して、または手動でSQLDataまたはORADataのJavaラッパー・クラスを作成します。

メソッド・サポート

外部名、コンストラクタ・コール、副作用のあるメンバー・ファンクションへのコールをサポートします。

型メソッドをJavaメソッドとして実装するデフォルト・クラスはありません。一部のメソッドはSQLでも実装できます。

型マッピング

型マッピングは、拡張SQLのCREATE TYPEコマンドによって自動的に行われます。ただし、SQLJオブジェクト型には、それを定義するJavaクラスがクライアント上にある必要があります。

型マップでのSQLとJavaの対応関係を登録します。対応関係にない場合、その型はoracle.sql.STRUCTとして実現されます。

継承

SQL階層をJavaクラス階層にマップするためのルールがあります。これらのルールの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

マッピング・ルールはありません。

その他の設計ヒント

この項では、Oracleオブジェクトの設計に関するその他のヒントを説明します。

階層内の列の置換え可能性と属性の数

属性データを格納するため、列または表が型Tである場合は、Oracleによって、Tの各属性に対して、列または表が置換え可能な場合は、Tの各サブタイプの各属性に対して、非表示列が追加されます。同様に、行の中のオブジェクト・インスタンスの型を追跡するため、非表示のtypeid列も追加されます。

1つの表内の列の数は、1,000に制限されています。属性の合計数が1,000に迫っている型階層では、その階層内の型の置換え可能な列を使用しているときにこの制限を超えてしまうというリスクがあります。この結果発生する問題を回避するため、属性の合計数が大きい階層については、次のオプションのいずれかを検討してください。

- ビューの使用

- REFの使用

- 階層の分割

型間の循環的依存関係

型間に循環的な依存関係を発生させることは避けてください。つまり、T型のメソッドが、型T1(T型を戻すメソッドを持つ)を戻すような状況を発生させないでください。

A オブジェクト・リレーショナル機能を使用したサンプル・アプリケーション

この付録では、ユーザー定義データ型(Oracleオブジェクト)の作成および使用方法の概要を説明するサンプル・アプリケーションを示します。まず、アプリケーションの開発にリレーショナル・モデルを使用し、次にオブジェクト・リレーショナル・モデルを使用します。

内容は次のとおりです。

- サンプル・アプリケーションの概要

- リレーショナル・モデルに基づくスキーマの実装

- オブジェクト・リレーショナル・モデルに基づくスキーマの実装

- オブジェクト型の進化

サンプル・アプリケーションの概要

ユーザー定義型とは、アプリケーション内のデータ構造および操作を形式化したスキーマ・オブジェクトのことです。

この付録の例では、オブジェクト型の定義、使用および進化における最も重要な点を説明します。オブジェクト型の作業で重要な点の1つは、オブジェクトに対して操作を実行するメソッドを作成することです。この例では、オブジェクト型メソッドの定義でPL/SQL言語を使用します。型の定義など、オブジェクト型の使用にかかわるそれ以外の部分ではSQLを使用します。

例では、顧客の発注書を管理するアプリケーションについて、様々なバージョンのデータベース・スキーマを作成します。まず、純粋なリレーショナル・バージョンを示し、次に同等のオブジェクト・リレーショナル・バージョンを示します。いずれのバージョンでも、顧客、発注書、明細項目などの同じ基本エンティティが使用されています。ただし、オブジェクト・リレーショナル・バージョンでは、これらのエンティティに対してオブジェクト型を作成し、それぞれのオブジェクト型のインスタンスをインスタンス化することによって、特定の顧客および発注書のデータを管理します。

PL/SQLおよびJavaを使用すると、特にコレクション要素のアクセスおよび操作の点で、この付録に示す以上の機能が実現できます。

OCI、Pro*C/C++、OO4OまたはOracle Data Providers for .NET(ODP.NET)を使用するクライアント・アプリケーションでは、その広範な機能を利用してオブジェクトおよびコレクションにアクセスし、それらをクライアント上で操作できます。

関連項目:

- ユーザー定義型のSQL構文および使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- PL/SQLの機能の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- Javaの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

- 『Oracle Call Interfaceプログラマーズ・ガイド』

- 『Pro*C/C++プログラマーズ・ガイド』

- 『Oracle Data Provider for .NET開発者ガイド』

リレーショナル・モデルに基づくスキーマの実装

この項では、図A-1に示す発注書スキーマのリレーショナル・バージョンを実装します。

エンティティとリレーションシップ

この例における基本エンティティは、次のとおりです。

- 顧客

- 販売する製品の在庫

- 発注書

図A-1のように、顧客には担当情報があるため、所在地と電話番号セットはその顧客に対して排他的です。アプリケーションでは、同じ所在地または電話番号に他の顧客を関連付けることはできません。顧客が所在地を変更すると、前の所在地は存在しなくなります。ユーザーが顧客でなくなった場合は、関連所在地が存在しなくなります。

顧客は、発注書に対して1対多リレーションシップを持ちます。1件の顧客が多数の発注を行うことはできますが、特定の発注を行う顧客は1件のみです。顧客は発注前に定義できるため、リレーションシップは必須ではなくオプションです。

同様に、発注書は在庫品目に対して多対多リレーションシップを持ちます。このリレーションシップはどの発注書にどの在庫品目が記載されているかを示すものではないため、E-Rには明細項目の表記法が使用されます。発注書には、1つ以上の明細項目を含める必要があります。各明細項目は、1件の発注書にのみ関連付けられています。明細項目と在庫品目の間には、在庫品目は明細書に記載しないか、1件または多数の明細項目に記載できますが、各明細項目が参照する在庫品目は1つのみであるというリレーションシップがあります。

図A-1 発注書アプリケーションのエンティティ関連ダイアグラム

リレーショナル・モデルに基づく表の作成

リレーショナル・アプローチでは、すべてが表に正規化されます。表名は、Customer_reltab、PurchaseOrder_reltabおよびStock_reltabです。

所在地の各部はCustomer_reltab表の列となります。電話番号を列として構造化することで、顧客が使用できる電話番号の数について任意の制限が設定されます。

リレーショナル・アプローチでは、明細項目が発注書から分離され、それぞれがPurchaseOrder_reltabおよびLineItems_reltabという固有の表に格納されます。

図A-1のように、明細項目は発注書および在庫品目の両方とリレーションシップを持ちます。これらは、PurchaseOrder_reltabおよびStock_reltabへの外部キーを使用してLineItems_reltab表に列として実装されます。

注意:
この項の表記規則では、リレーショナル表の名前に接尾辞_reltabが追加されています。このようにわかりやすい表記法を使用することで、コードを容易にメンテナンスできます。
表(_tab)と型(_typ)を区別すると便利です。それ以外でも、必要な名前を選択できます。オブジェクト・リレーショナル構造のメリットの1つは、対応する現実のオブジェクトを密接にモデル化する名前を指定できることです。

以降の各項では、リレーショナル・アプローチに基づいて作成された表について説明します。

Customer_reltab

Customer_reltab表の定義は、次のとおりです。

例A-1 Customer_reltab表の作成

CREATE TABLE Customer_reltab (
CustNo                NUMBER NOT NULL,
CustName              VARCHAR2(200) NOT NULL,
Street                VARCHAR2(200) NOT NULL,
City                  VARCHAR2(200) NOT NULL,
State                 CHAR(2) NOT NULL,
Zip                   VARCHAR2(20) NOT NULL,
Phone1                VARCHAR2(20),
Phone2                VARCHAR2(20),
Phone3                VARCHAR2(20),
PRIMARY KEY (CustNo));

この表Customer_reltabには、顧客に関するすべての情報、つまり、顧客固有の情報(NOT NULL制約で定義)と重要でない情報がすべて格納されます。この表の定義によると、アプリケーションでは各顧客に出荷先所在地が必要です。

エンティティ関連(E-R)ダイアグラムは発注する顧客を示していましたが、この表では顧客と発注書の間のリレーションシップは許可されていません。このリレーションシップは発注書別に管理する必要があります。

PurchaseOrder_reltab

PurchaseOrder_reltab表の定義は、次のとおりです。

例A-2 PurchaseOrder_reltab表の作成

CREATE TABLE PurchaseOrder_reltab (
PONo        NUMBER, /* purchase order no */
Custno      NUMBER references Customer_reltab, /*  Foreign KEY referencing
customer */
OrderDate   DATE, /*  date of order */
ShipDate    DATE, /* date to be shipped */
ToStreet    VARCHAR2(200), /* shipto address */
ToCity      VARCHAR2(200),
ToState     CHAR(2),
ToZip       VARCHAR2(20),
PRIMARY KEY(PONo));

PurchaseOrder_reltabでは、Customer_reltabのCustNoキーを参照する外部キー(FK)列CustNoを使用して顧客と発注書とのリレーションシップを管理します。PurchaseOrder_reltab表には、関連明細項目に関する情報は含まれていません。次項の明細項目表では、発注番号を使用して明細項目を親発注書に関連付けます。

Stock_reltab

Stock_reltab表の定義は、次のとおりです。

例A-3 Stock_reltab表の作成

CREATE TABLE Stock_reltab (
StockNo      NUMBER PRIMARY KEY,
Price        NUMBER,
TaxRate      NUMBER);

LineItems_reltab

LineItems_reltab表の定義は、次のとおりです。

例A-4 LineItems_reltab表の作成

CREATE TABLE LineItems_reltab (
LineItemNo           NUMBER,
PONo                 NUMBER REFERENCES PurchaseOrder_reltab,
StockNo              NUMBER REFERENCES Stock_reltab,
Quantity             NUMBER,
Discount             NUMBER,
PRIMARY KEY (PONo, LineItemNo));

注意:
Stock_reltab表とPurchaseOrder_reltab表は、LineItems_reltab表の前に作成する必要があります。

表名には、この表に明細項目の集合が保持されることをコードを読むユーザーに対して強調するために、複数形であるLineItems_reltabが使用されています。

エンティティ関連ダイアグラムに示すように、明細項目のリストは発注書および在庫品目の両方とのリレーションシップを持ちます。これらのリレーションシップは、LineItems_reltabで次の2つの外部キー列を使用して管理されます。

- PONo: PurchaseOrder_reltabのPONo列を参照します。

- StockNo: Stock_reltabのStockNo列を参照します。

リレーショナル・モデルに基づく値の挿入

アプリケーションでは、次のような文を使用して表にデータを挿入します。

例A-5 在庫の設定

INSERT INTO Stock_reltab VALUES(1004, 6750.00, 2);
INSERT INTO Stock_reltab VALUES(1011, 4500.23, 2);
INSERT INTO Stock_reltab VALUES(1534, 2234.00, 2);
INSERT INTO Stock_reltab VALUES(1535, 3456.23, 2);

例A-6 顧客の登録

INSERT INTO Customer_reltab
VALUES (1, 'Jean Nance', '2 Avocet Drive',
'Redwood Shores', 'CA', '95054',
'415-555-0102', NULL, NULL);

INSERT INTO Customer_reltab
VALUES (2, 'John Nike', '323 College Drive',
'Edison', 'NJ', '08820',
'609-555-0190', '201-555-0140', NULL);

例A-7 発注処理

INSERT INTO PurchaseOrder_reltab
VALUES (1001, 1, SYSDATE, '10-MAY-1997',
NULL, NULL, NULL, NULL);

INSERT INTO PurchaseOrder_reltab
VALUES (2001, 2, SYSDATE, '20-MAY-1997',
'55 Madison Ave', 'Madison', 'WI', '53715');

例A-8 明細項目の詳細入力

INSERT INTO LineItems_reltab VALUES(01, 1001, 1534, 12,  0);
INSERT INTO LineItems_reltab VALUES(02, 1001, 1535, 10, 10);
INSERT INTO LineItems_reltab VALUES(01, 2001, 1004,  1,  0);
INSERT INTO LineItems_reltab VALUES(02, 2001, 1011,  2,  1);

リレーショナル・モデルに基づくデータの問合せ

アプリケーションでは、次のような問合せを実行できます。

例A-9 特定の発注書に関する顧客および明細項目データの取得

SELECT   C.CustNo, C.CustName, C.Street, C.City, C.State,
C.Zip, C.phone1, C.phone2, C.phone3,
P.PONo, P.OrderDate,
L.StockNo, L.LineItemNo, L.Quantity, L.Discount
FROM    Customer_reltab C,
PurchaseOrder_reltab P,
LineItems_reltab L
WHERE   C.CustNo = P.CustNo
AND    P.PONo = L.PONo
AND    P.PONo = 1001;

例A-10 発注書の合計値の取得

SELECT     P.PONo, SUM(S.Price * L.Quantity)
FROM      PurchaseOrder_reltab P,
LineItems_reltab L,
Stock_reltab S
WHERE     P.PONo = L.PONo
AND      L.StockNo = S.StockNo
GROUP BY P.PONo;

例A-11 在庫品目1004に関する発注書および明細項目データの取得

SELECT    P.PONo, P.CustNo,
L.StockNo, L.LineItemNo, L.Quantity, L.Discount
FROM     PurchaseOrder_reltab P,
LineItems_reltab     L
WHERE    P.PONo = L.PONo
AND    L.StockNo = 1004;

リレーショナル・モデルに基づくデータの更新

アプリケーションでは、次のような文を実行してデータを更新できます。

例A-12 発注書1001および在庫品目1534の数量の更新

UPDATE LineItems_reltab
SET      Quantity = 20
WHERE    PONo     = 1001
AND      StockNo  = 1534;

リレーショナル・モデルに基づくデータの削除

アプリケーションでは、例A-13のような文を実行してデータを削除できます。

例A-13 リレーショナル・モデルに基づく発注書1001の削除

DELETE
FROM   LineItems_reltab
WHERE  PONo = 1001;

DELETE
FROM   PurchaseOrder_reltab
WHERE  PONo = 1001;

オブジェクト・リレーショナル・モデルに基づくスキーマの実装

オブジェクト・リレーショナル・アプローチも、「エンティティとリレーションシップ」に示したのと同じE-Rから始まります。これらのE-Rを次のクラス図のようにオブジェクト指向の観点から見ると、実社会のさらに多くの構造をデータベース・スキーマに変換できます。

図A-2 発注書アプリケーションのクラス図

オブジェクト・リレーショナル・アプローチでは、所在地や複数の電話番号を関連性のないリレーショナル表列に分割するかわりに、所在地全体および電話番号リスト全体を表す型を定義します。同様に、このアプローチでは明細項目と発注書を個別に格納するかわりに、ネストした表を使用して格納します。

主なエンティティ(顧客、在庫および発注書)はオブジェクト型になります。オブジェクト型間のなんらかのリレーションシップを表すためにオブジェクト参照が使用されます。コレクション型(VARRAYおよびネストした表)は、複数値属性をモデル化するために使用されます。

注意:
この付録では、新しいオブジェクト・リレーショナル・スキーマを作成してオブジェクト・リレーショナル・インタフェースを実装します。このアプローチでは、データ格納用のオブジェクト表を作成します。または、オブジェクト表のかわりにオブジェクト・ビューを使用して、リレーショナル表に格納されている既存のデータへのオブジェクト・リレーショナル・インタフェースを実装することもできます。オブジェクト・ビューについては、第6章を参照してください。

型の定義

オブジェクト型は、CREATE TYPE文で作成します。たとえば、次の文では、StockItem_objtyp型が作成されます。

例A-14 StockItem_objtypオブジェクトの作成

CREATE TYPE StockItem_objtyp AS OBJECT (
StockNo    NUMBER,
Price      NUMBER,
TaxRate    NUMBER
);
/

StockItem_objtyp型のインスタンスは、顧客が発注する在庫品目を表すオブジェクトです。これらは3つの数値属性を持ちます。StockNoは主キーです。

型を定義する順序によって違いが生じる場合があります。参照先の型を定義してから、その型を参照する他の型を定義するのが理想的です。

たとえば、LineItem_objtyp型はStockItem_objtypのオブジェクトへのREFである属性を含むことでStockItem_objtypを参照(前提と)します。このことは、LineItem_objtyp型を作成する文で確認できます。

例A-15 LineItem_objtypオブジェクトの作成

CREATE TYPE LineItem_objtyp AS OBJECT (
LineItemNo   NUMBER,
Stock_ref    REF StockItem_objtyp,
Quantity     NUMBER,
Discount     NUMBER
);
/

LineItem_objtyp型のインスタンスは、明細項目を表すオブジェクトです。これらは3つの数値属性と1つのREF属性を持ちます。LineItem_objtypにより明細項目エンティティがモデル化され、対応する在庫オブジェクトへのオブジェクト参照が含まれます。

型間の参照が入り組んでいるために、ある型を作成する前にその前提となる型をすべて作成することが困難な場合や不可能な場合があります。このような状況に対処するために、不完全型と呼ばれる型を作成し、参照先として作成する他の型のプレースホルダとして使用できます。これにより、他の型を作成した後に、不完全型に戻って完全型で置き換えることができます。

たとえば、StockItem_objtypの作成前にLineItem_objtypを作成する必要がある場合は、次のような文を使用してLineItem_objtypを不完全型として作成します。

CREATE TYPE LineItem_objtyp;

不完全型の作成に使用されるCREATE TYPE文の書式には、AS OBJECT句がなく、属性の指定もありません。

不完全型を完全な定義で置き換えるには、次の例に示すようにOR REPLACE句を挿入します。

例A-16 LineItem_objtypオブジェクトの置換

CREATE OR REPLACE TYPE LineItem_objtyp AS OBJECT (
LineItemNo   NUMBER,
Stock_ref    REF StockItem_objtyp,
Quantity     NUMBER,
Discount     NUMBER
);
/

OR REPLACE句は、置き換える不完全型がない場合も使用できます。

ここで、スキーマに必要な残りの型を作成します。次の文では、電話番号リストの配列型を定義します。

例A-17 PhoneList_vartyp型の作成

CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20);
/

PhoneList_vartyp型のデータ単位(インスタンス)は、それぞれがVARCHAR2型のデータ項目で表される最大10個の電話番号のVARRAYです。

VARRAYまたはネストした表を使用して、電話番号リストを格納できます。この場合のリストは、1件の顧客の連絡先電話番号のセットです。次の理由から、VARRAYの方がネストした表よりも適しています。

- 番号の順序が重要な場合があります。VARRAYは順序付きですがネストした表には順序がありません。

- 特定の顧客の電話番号は少数です。VARRAYの場合は、最大要素数(この例で10)を事前に指定する必要があります。特別なサイズ制限のないネストした表よりも、記憶域が効率的に使用されます。

- ネストした表の問合せはできますが、VARRAYの問合せはできません。ただし、電話番号リストを問い合せる理由はないため、ネストした表を使用してもメリットはありません。

通常、順序付けと境界が設計上の重要課題でなければ、設計者は次の経験則に従ってVARRAYとネストした表のどちらを使用するかを選択できます。つまり、コレクションの問合せが必要な場合はネストした表を使用し、コレクション全体を取り出す意図がある場合はVARRAYを使用します。

関連項目:
VARRAYとネストした表に関する設計上の考慮点の詳細は、第9章「Oracleオブジェクトの設計上の考慮点」を参照してください。

次の文では、所在地を表すオブジェクト型Address_objtypを定義します。

例A-18 Address_objtypオブジェクトの作成

CREATE TYPE Address_objtyp AS OBJECT (
Street         VARCHAR2(200),
City           VARCHAR2(200),
State          CHAR(2),
Zip            VARCHAR2(20)
)
/

所在地の属性はすべて、単純化された郵送先住所の各部を表す文字列です。

次の文では、他のオブジェクト型を構築ブロックとして使用するオブジェクト型Customer_objtypを定義します。

例A-19 Customer_objtypオブジェクトの作成

CREATE TYPE Customer_objtyp AS OBJECT (
CustNo           NUMBER,
CustName         VARCHAR2(200),
Address_obj      Address_objtyp,
PhoneList_var    PhoneList_vartyp,

ORDER MEMBER FUNCTION
compareCustOrders(x IN Customer_objtyp) RETURN INTEGER
) NOT FINAL;
/

Customer_objtyp型のインスタンスは、特定の顧客に関する情報ブロックを表すオブジェクトです。Customer_objtypオブジェクトの属性は、数値、文字列、Address_objtypオブジェクトおよびPhoneList_vartyp型のVARRAYです。

NOT FINAL句を使用すると、必要に応じて後からcustomer型のサブタイプを作成できます。デフォルトでは、型はFINALとして作成されますが、これは、その型がサブタイプを導出することでそれ以上特化できないことを意味します。より特殊な顧客に関するCustomer_objtypのサブタイプの定義については、この付録で後述します。

各Customer_objtypオブジェクトには、2種類の比較メソッドの一方であるオーダー・メソッドも関連付けられています。Oracleでは、2つのCustomer_objtypオブジェクトの比較を必要とする場合に、暗黙的にcompareCustOrdersメソッドが起動されて比較が実行されます。

注意:
比較メソッドを実装するPL/SQLについては、「compareCustOrdersメソッド」を参照してください。

2種類の比較メソッドとは、マップ・メソッドとオーダー・メソッドです。このアプリケーションでは、説明のためにそれぞれ1つずつ使用します。

ORDERメソッドは比較対象となる2つのオブジェクトごとにコールする必要がありますが、マップ・メソッドはオブジェクトごとに1回コールされます。通常、一連のオブジェクトをソートする場合、ORDERメソッドのコール回数の方がマップ・メソッドのコール回数よりも多くなります。

関連項目:

- マップ・メソッドとオーダー・メソッドの詳細は、第2章「Oracleオブジェクトの基本コンポーネント」を参照してください。

- プラグマ宣言の使用方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

次の文では、ネストした明細項目表の型を定義します。各発注書では、このネストした表の型のインスタンスを使用して、その発注書の明細項目が格納されます。

例A-20 LineItemList_ntabtyp型の作成

CREATE TYPE LineItemList_ntabtyp AS TABLE OF LineItem_objtyp;
/

この型のインスタンスは、各行にLineItem_objtyp型のオブジェクトが含まれるネストした表オブジェクト(ネストした表)です。次の理由から、複数値明細項目リストを表すには、LineItem_objtypオブジェクトのVARRAYよりもネストした明細項目表の方が適しています。

- ほとんどのアプリケーションでは、明細項目の内容を問い合せる必要があります。明細項目がネストした表に格納されていれば、この問合せにSQLを使用できますが、VARRAYに格納されている場合はSQLを使用できません。

- アプリケーションで明細項目データに索引付けする必要がある場合、ネストした表は使用できますが、VARRAYは使用できません。

- 明細項目の格納順序は重要でないと推定される場合、問合せ時に必要に応じて明細項目番号で順序付けできます。

- 発注書の明細項目数には、事実上の上限はありません。VARRAYを使用するには、要素数の任意の上限を指定する必要があります。

次の文では、オブジェクト型PurchaseOrder_objtypを定義します。

例A-21 PurchaseOrder_objtypオブジェクトの作成

CREATE TYPE PurchaseOrder_objtyp AUTHID CURRENT_USER AS OBJECT (
PONo                 NUMBER,
Cust_ref             REF Customer_objtyp,
OrderDate            DATE,
ShipDate             DATE,
LineItemList_ntab    LineItemList_ntabtyp,
ShipToAddr_obj       Address_objtyp,

MAP MEMBER FUNCTION
getPONo RETURN NUMBER,

MEMBER FUNCTION
sumLineItems RETURN NUMBER
);
/

PurchaseOrder_objtyp型のインスタンスは、発注書を表すオブジェクトです。この種のオブジェクトには、Customer_objtypへのREF、Address_objtypオブジェクト、LineItem_objtyp型に基づくLineItemList_ntabtyp型のネストした表など、6つの属性があります。PONoは主キーで、Cust_refは外部キーです。

PurchaseOrder_objtyp型のオブジェクトには、2つのメソッドgetPONoおよびsumLineItemsがあります。一方のgetPONoは、2種類の比較メソッドの1つであるマップ・メソッドです。マップ・メソッドは、オブジェクト内のレコードの順序における指定されたレコードの相対位置を戻します。そのため、Oracleでは、2つのPurchaseOrder_objtypオブジェクトの比較が必要になると、暗黙的にgetPONoメソッドがコールされて比較が実行されます。

2つのプラグマ宣言は、2つのメソッドに必要なデータベースへのアクセス・タイプ情報をPL/SQLに提供します。

文には、メソッドgetPONoおよびsumLineItemsを実装する実際のPL/SQLプログラムは含まれていません。「メソッド定義」を参照してください。

メソッド定義

型にメソッドがない場合、その定義はCREATE TYPE文のみで構成されます。ただし、メソッドを持つ型の場合は、型の定義を完了するために型本体も定義する必要があります。そのためにはCREATE TYPE BODY文を使用します。CREATE TYPEの場合と同様に、OR REPLACE句を挿入できます。既存の型本体を新規の型本体で置き換える場合は、メソッドを変更するために、この句を挿入する必要があります。

次の文では、PurchaseOrder_objtyp型の本体を定義します。この文は、型のメソッドを実装するPL/SQLプログラムを提供します。

例A-22 PurchaseOrder_objtyp型本体の作成

CREATE OR REPLACE TYPE BODY PurchaseOrder_objtyp AS

MAP MEMBER FUNCTION getPONo RETURN NUMBER is
BEGIN
RETURN PONo;
END;

MEMBER FUNCTION sumLineItems RETURN NUMBER is
i             INTEGER;
StockVal      StockItem_objtyp;
Total         NUMBER := 0;

BEGIN
FOR i in 1..SELF.LineItemList_ntab.COUNT LOOP
UTL_REF.SELECT_OBJECT(LineItemList_ntab(i).Stock_ref,StockVal);
Total := Total + SELF.LineItemList_ntab(i).Quantity * StockVal.Price;
END LOOP;
RETURN Total;
END;
END;
/

getPONoメソッド

getPONoメソッドは、単にこのメソッドをコールするPurchaseOrder_objtyp型のインスタンスのPONo属性の値(発注書番号)を戻します。この種のgetメソッドを使用すると、内部表現に変更があった場合にも、オブジェクトを使用するコードを再加工する必要がありません。

sumLineItemsメソッド

sumLineItemsメソッドは、多数のオブジェクト・リレーショナル機能を使用します。

- 前述のように、sumLineItemsメソッドの基本機能は、関連PurchaseOrder_objtypオブジェクトの明細項目の値の合計を戻すことです。各ファンクションのパラメータとして暗黙的に作成されるSELFキーワードにより、そのオブジェクトを参照できます。

- COUNTキーワードは、PL/SQL表または配列の要素数のカウントを示します。この例ではLOOPと併用されており、アプリケーションはコレクション内の全要素(この場合は発注書の項目)を反復します。この方法で、SELF.LineItemList_ntab.COUNTはネストした表内でPurchaseOrder_objtypオブジェクトのLineItemList_ntab属性(ここではSELFで表現)と一致する要素の数をカウントします。

- 実装内ではパッケージUTL_REFのメソッドが使用されます。Oracleでは、PL/SQLプログラム内でのREFの暗黙的な参照解除はサポートされないため、UTL_REFメソッドが必要です。UTL_REFパッケージは、オブジェクト参照を操作するメソッドを提供します。ここでは、Stock_refに対応するStockItem_objtypオブジェクトを取得するためにSELECT_OBJECTメソッドがコールされます。

AUTHID CURRENT_USER構文では、PurchaseOrder_objtypが実行者権限を使用して定義されていることが指定されます。つまり、メソッドは型を定義したユーザーの権限ではなく現行のユーザーの権限で実行されます。

- PL/SQL変数StockValはStockItem_objtyp型です。この変数は、UTL_REF.SELECT_OBJECTにより次を参照するオブジェクトに設定されます。
(LineItemList_ntab(i).Stock_ref)

このオブジェクトは、現在選択されている明細項目で参照される実際の在庫品目です。

- 問題の在庫品目を取り出した後、次のステップは原価を計算することです。プログラムでは、在庫品目の原価をStockItem_objtypオブジェクトのPrice属性であるStockVal.Priceとして参照します。ただし、品目の原価を計算するために品目の受注数量も知る必要があります。アプリケーションでは、条件LineItemList_ntab(i).Quantityは現在選択されているLineItem_objtypオブジェクトのQuantity属性を表します。

メソッド・プログラムの残りの部分は、明細項目の値の合計を計算するループです。メソッドは合計を戻します。

compareCustOrdersメソッド

次の文では、Customer_objtypオブジェクト型の型本体でcompareCustOrdersメソッドを定義します。

例A-23 Customer_objtyp型本体の作成

CREATE OR REPLACE TYPE BODY Customer_objtyp AS
ORDER MEMBER FUNCTION
compareCustOrders (x IN Customer_objtyp) RETURN INTEGER IS
BEGIN
RETURN CustNo - x.CustNo;
END;
END;
/

前述のように、オーダー・メソッドcompareCustOrdersの操作では、2つの顧客発注に関する情報が比較されます。このメソッドは入力引数としてCustomer_objtypオブジェクトをもう1つ取り、2つのCustNo番号の違いを戻します。戻り値は次のとおりです。

- 固有のオブジェクトのCustNo値の方が小さい場合は負の数。

- 固有のオブジェクトのCustNo値の方が大きい場合は正の数。

- 2つのオブジェクトのCustNo値が同一の場合は0 (ゼロ)。この場合は、両方の発注が同じ顧客に関連付けられています。

戻り値が正、負または0(ゼロ)のいずれであるかは、顧客番号の相対順序を示します。たとえば、通常、小さい番号は大きい番号よりも前に作成されます。ORDERメソッドの入力引数(SELFと明示的引数)がNULLの場合、ORDERメソッドはコールされず、結果は単にNULLとして処理されます。

これで、発注書スキーマのオブジェクト・リレーショナル・バージョンについて、すべてのオブジェクト型を定義したことになります。実際の発注書データを含めるこれらの型のインスタンスは作成しておらず、この種のデータを格納する表も作成していません。次の項では、この作成方法について説明します。

オブジェクト表の作成

オブジェクト型の作成は、表の作成とは異なります。型を作成する場合は、論理構造を定義するのみで、記憶域は作成しません。データへのオブジェクト・リレーショナル・インタフェースを使用するには、データをオブジェクト表に格納するか、リレーショナル表に残しておいてオブジェクト・ビューからアクセスするかに関係なく、オブジェクト型を作成する必要があります。オブジェクト・ビューとオブジェクト表は、どちらもオブジェクト型を前提とします。オブジェクト表またはオブジェクト・ビューは、常に特定のオブジェクト型の表またはビューです。この点では、常に指定のデータ型を持つリレーショナル列に似ています。

関連項目:
オブジェクト・ビューの詳細は、第6章「オブジェクト・モデルのリレーショナル・データへの適用」を参照してください。

リレーショナル列と同様に、オブジェクト表に含めることができるのは、表と同一の宣言された型のオブジェクト・インスタンスなど、1種類の行のみです。(また、表が代入可能な場合は、宣言された型のサブタイプのインスタンスも含めることができます。)

オブジェクト表の各行は1つのオブジェクト・インスタンスです。そのため、ある意味では、オブジェクト表は宣言されたオブジェクト型の1列のみで構成されることになります。ただし、これはリレーショナル表の場合と異なるわけではありません。リレーショナル表の各行も、理論上は1つのエンティティ(リレーショナルCustomers表内の顧客など)を表します。リレーショナル表の各列には、このエンティティの属性データが格納されます。

同様に、オブジェクト表では、オブジェクト型の属性は挿入および選択可能な列にマップされます。主な違いは、オブジェクト表の場合、データが表の型で定義された構造で格納される(および取出し可能である)ため、きわめて単純な問合せでデータのマルチレベル構造全体を取り出すことができるという点にあります。

オブジェクト表Customer_objtab

次の文では、Customer_objtyp型のオブジェクトを保持するオブジェクト表Customer_objtabを定義します。

例A-24 Customer_objtab表の作成

CREATE TABLE Customer_objtab OF Customer_objtyp (CustNo PRIMARY KEY)
OBJECT IDENTIFIER IS PRIMARY KEY;

リレーショナル表とは異なり、オブジェクト表の作成時には、データ型(格納されるオブジェクトの型)を指定します。

表には、次のようにCustomer_objtypの属性ごとに1列があります。

CustNo NUMBER /* Primary key */
CustName VARCHAR2(200)
Address_obj Address_objtyp
PhoneList_var PhoneList_vartyp

これらの型の定義は、例A-18「Address_objtypオブジェクトの作成」および例A-17「PhoneList_vartyp型の作成」を参照してください。

図A-3 表Customer_objtabのオブジェクト・リレーショナル表現

オブジェクト表のテンプレートとしてのオブジェクト・データ型

Customer_objtyp型があるため、同じ型の多数のオブジェクト表を作成できます。たとえば、同じCustomer_objtyp型のオブジェクト表Customer_objtab2を作成できます。

複数の表を作成する場合は、バリエーションを導入できます。Customer_objtabの作成に使用した文では、CustNo列に主キー制約を定義しました。この制約は、このオブジェクト表にのみ適用されます。同じ型の別のオブジェクト表には、この制約がない場合があります。

オブジェクト識別子および参照

Customer_objtabには、行オブジェクトとして表される顧客オブジェクトが含まれています。Oracleでは、行オブジェクトを参照可能にでき、これは、他の行オブジェクトまたはリレーショナル行からオブジェクト識別子(OID)を使用して参照できることを意味します。たとえば、発注書行オブジェクトでは、オブジェクト参照を使用して顧客行オブジェクトを参照できます。オブジェクト参照は、REF型で表されるシステム生成値であり、行オブジェクトの一意OIDに基づきます。

Oracleでは、各行オブジェクトに一意OIDが必要です。一意OID値をシステム生成として指定するか、行オブジェクトの主キーを一意OIDとして機能するように指定できます。この指定を行うには、CREATE TABLE文の実行時にOBJECT IDENTIFIER IS PRIMARY KEYまたはOBJECT IDENTIFIER IS SYSTEM GENERATEDを指定します。後者がデフォルトです。主キー値がデフォルトである16バイトのシステム生成識別子より小さい場合は、オブジェクト識別子として主キーを使用する方が効率的です。この例では、行オブジェクト識別子として主キーを使用しています。

埋込みオブジェクトを持つオブジェクト表

Customer_objtabのAddress_obj列にAddress_objtypオブジェクトが含まれていることに注意してください。この図が示すように、オブジェクト型は、それ自体がオブジェクト型である属性を持つことができます。オブジェクト表について宣言された型のオブジェクト・インスタンスが行オブジェクトと呼ばれるのは、1つのオブジェクト・インスタンスが表の行全体を占めるためです。ただし、Address_obj列にあるような埋込みオブジェクトは、列オブジェクトと呼ばれます。この種のオブジェクトは、行全体を占めないという点が行オブジェクトとは異なります。そのため参照不可であり、REFのターゲットにすることはできません。また、NULLにすることができます。

Address_objtypオブジェクトの属性は組込み型です。複合型ではなくスカラーである(つまり、固有の属性を持つオブジェクト型ではない)ため、ブランチの終了を表すことを反映するためにリーフ・レベル属性と呼ばれます。Address_objtypオブジェクトとその属性の列は、オブジェクト表Customer_objtabに作成されます。これらの列の参照またはナビゲートには、ドット表記法を使用できます。たとえば、Zip列に索引を作成する場合は、Address.Zipとして参照できます。

PhoneList_var列には、PhoneList_vartyp型のVARRAYが含まれています。PhoneList_vartyp型の各オブジェクトは、それぞれがVARCHAR2型のデータ項目で表される最大10個の電話番号のVARRAYとして定義してあります。例A-17を参照してください。

PhoneList_vartyp型の各VARRAYには最大200文字(10x20)と少量のオーバーヘッドを格納できるため、OracleではVARRAYがPhoneList_var列に1つのデータ単位として格納されます。4000バイト以内のVARRAYはインラインのBLOBに格納され、これは、VARRAY値の一部が表の外部に格納される可能性があることを意味します。

オブジェクト表Stock_objtab

次の文では、StockItem_objtypオブジェクトのオブジェクト表を作成します。

例A-25 Stock_objtab表の作成

CREATE TABLE Stock_objtab OF StockItem_objtyp (StockNo PRIMARY KEY)
OBJECT IDENTIFIER IS PRIMARY KEY;

この表の各行は、次の3つの数値属性を持つStockItem_objtypオブジェクトです。

StockNo NUMBER
Price NUMBER
TaxRate NUMBER

Oracleでは、属性ごとに1列が作成されます。CREATE TABLE文では、StockNo列に主キー制約が適用され、主キーを行オブジェクトの識別子として使用するように指定されます。

オブジェクト表PurchaseOrder_objtab

次の文では、PurchaseOrder_objtypオブジェクトのオブジェクト表を定義します。

例A-26 PurchaseOrder_objtab表の作成

CREATE TABLE PurchaseOrder_objtab OF PurchaseOrder_objtyp (  /* Line 1 */
PRIMARY KEY (PONo),                                       /* Line 2 */
FOREIGN KEY (Cust_ref) REFERENCES Customer_objtab)        /* Line 3 */
OBJECT IDENTIFIER IS PRIMARY KEY                          /* Line 4 */
NESTED TABLE LineItemList_ntab STORE AS PoLine_ntab (     /* Line 5 */
(PRIMARY KEY(NESTED_TABLE_ID, LineItemNo))              /* Line 6 */
ORGANIZATION INDEX COMPRESS)                            /* Line 7 */
RETURN AS LOCATOR                                         /* Line 8 */
/

このCREATE TABLE文では、PurchaseOrder_objtabオブジェクト表が作成されます。各行の内容は次のとおりです。

行1:

CREATE TABLE PurchaseOrder_objtab OF PurchaseOrder_objtyp (

この行は、表の各行がPurchaseOrder_objtypオブジェクトであることを示します。PurchaseOrder_objtypオブジェクトの属性は次のとおりです。

PONo NUMBER
Cust_ref REF Customer_objtyp
OrderDate DATE
ShipDate DATE
LineItemList_ntab LineItemList_ntabtyp
ShipToAddr_obj Address_objtyp

これらの型の定義は、例A-19「Customer_objtypオブジェクトの作成」および例A-20「LineItemList_ntabtyp型の作成」を参照してください。

図A-4 表PurchaseOrder_objtabのオブジェクト・リレーショナル表現

行2:

PRIMARY KEY (PONo),

この行は、PONo属性を表の主キーとして指定します。

行3:

FOREIGN KEY (Cust_ref) REFERENCES Customer_objtab)

この行は、Cust_ref列の参照制約を指定します。この参照制約は、リレーショナル表に対して指定される制約と同様です。制約がない場合、REF列では任意の行オブジェクトを参照できます。ただし、この場合、Cust_ref REFで参照できるのはCustomer_objtabオブジェクト表の行オブジェクトのみです。

行4:

OBJECT IDENTIFIER IS PRIMARY KEY

この行は、PurchaseOrder_objtabオブジェクト表の主キーが行のOIDとして使用されることを示します。

行5から8:

NESTED TABLE LineItemList_ntab STORE AS PoLine_ntab (
(PRIMARY KEY(NESTED_TABLE_ID, LineItemNo))
ORGANIZATION INDEX COMPRESS)
RETURN AS LOCATOR

この4行は、ネストした表の列LineItemList_ntabの記憶域の指定とプロパティに関係しています。ネストした表の行は、別の記憶表に格納されます。この記憶表をユーザーが直接問い合せることはできませんが、メンテナンスのためにDDL文で参照することはできます。記憶表の非表示列NESTED_TABLE_IDでは、各行が対応する親行と一致します。特定の親に属するネストした表の全要素は同じNESTED_TABLE_ID値を持ちます。たとえば、PurchaseOrder_objtabの特定の行のネストした表の要素は、すべて同じNESTED_TABLE_ID値を持ちます。PurchaseOrder_objtabの別の行に属するネストした表の要素は、異なるNESTED_TABLE_ID値を持ちます。

前述のCREATE TABLEの例では、行5はネストした表LineItemList_ntabの行が別の表(記憶表)PoLine_ntabに格納されることを示します。STORE AS句で記憶表に対する制約と記憶域を指定することもできます。この例で、行7は記憶表が索引構成表(IOT)であることを示します。通常、ネストした表の行をIOTに格納すると、同じ親に属している行がクラスタ化されるというメリットがあります。IOTにCOMPRESSが指定されているため、記憶域が節約されますが、その理由は、COMPRESSを指定しなければ、IOTのキーのNESTED_TABLE_ID部分が親の行オブジェクトの行ごとに繰り返されるためです。ただし、COMPRESSを指定すると、NESTED_TABLE_IDは親の行オブジェクトごとに一度のみ格納されます。

関連項目:
ネストした表をIOTとして構成するメリット、ネストした表の圧縮を指定するメリット、ネストした表の記憶域全般の詳細は、「ネストした表の記憶域」を参照してください。

行6では、NESTED_TABLE_IDおよびLineItemNo属性が2つの目的で記憶表の主キーとして指定されています。第1の目的はIOTのキーを指定すること、第2の目的はネストした表のLineItemNo列の一意性を親表の各行内で規定することです。この文では、LineItemNo列をキーに含めることで、LineItemNo列に各発注書内の個別値が確実に含まれるようになります。

行8は、ネストした表LineItemList_ntabが取得時にロケータ形式で戻されることを示します。LOCATORを指定しなければ、デフォルトはVALUEで、ロケータのみでなくネストした表全体が戻されます。ネストした表のコレクションに多数の要素が含まれている場合は、それらを含んでいる行オブジェクトまたは列が選択されたときに、ネストされた表全体を戻すのは非効率的です。

ネストした表のロケータが戻されるように指定すると、Oracleでは実際のコレクション値へのロケータのみをクライアントに送信できます。アプリケーションでは、OCICollIsLocatorまたはUTL_COLL.IS_LOCATORインタフェースをコールして、フェッチされたネストした表がロケータ形式であるか値形式であるかを検出できます。ロケータが戻されることを確認した後、アプリケーションでは問合せにロケータを使用して、ネストした表の行要素のうち必要なサブセットのみをフェッチできます。このような、ネストした表の行のロケータ・ベースの取得は、ネストした表の値またはコピー・セマンティクスを保つために、オリジナルの文のスナップショットに基づきます。つまり、ネストした表の行要素のサブセットをフェッチするためにロケータが使用される場合、ネストした表のスナップショットには、ロケータが最初に取得されたときのネストした表が反映されます。

ここで再び「メソッド定義」に示したPurchaseOrder_objtypのsumLineItemsメソッドの実装を考えてみます。その実装は、ネストした表LineItemList_ntabがVALUEとして戻されることを前提としていました。大きいネストした表を効率的に処理し、PurchaseOrder_objtabのネストした表がロケータとして戻されるという事実を活用するには、sumLineItemsメソッドを次のように書き換える必要があります。

例A-27 PurchaseOrder_objtyp型本体の置換

CREATE OR REPLACE TYPE BODY PurchaseOrder_objtyp AS

MAP MEMBER FUNCTION getPONo RETURN NUMBER is
BEGIN
RETURN PONo;
END;

MEMBER FUNCTION sumLineItems RETURN NUMBER IS
i          INTEGER;
StockVal   StockItem_objtyp;
Total      NUMBER := 0;

BEGIN
IF (UTL_COLL.IS_LOCATOR(LineItemList_ntab)) -- check for locator
THEN
SELECT SUM(L.Quantity * L.Stock_ref.Price) INTO Total
FROM   TABLE(CAST(LineItemList_ntab AS LineItemList_ntabtyp)) L;
ELSE
FOR i in 1..SELF.LineItemList_ntab.COUNT LOOP
UTL_REF.SELECT_OBJECT(LineItemList_ntab(i).Stock_ref,StockVal);
Total := Total + SELF.LineItemList_ntab(i).Quantity *
StockVal.Price;
END LOOP;
END IF;
RETURN Total;
END;
END;
/

書き換えたsumLineItemsメソッドは、UTL_COLL.IS_LOCATORファンクションを使用して、ネストした表の属性LineItemList_ntabがロケータとして戻されるかどうかをチェックします。条件がTRUEに評価されると、ネストした表のロケータはTABLE式を使用して問合せされます。

注意:
SQLコンパイル・エンジンにコレクション属性(またはパラメータまたは変数)の実際の型を指示して問合せをコンパイルできるように、現在、TABLE式にはCAST式が必要です。

ネストした表のロケータを問い合せる方が、発注書の大きい明細項目リストを効率的に処理できます。LineItemList_ntabを反復する前述のコードは、ネストした表がVALUEとして戻される場合に対処するために残されています。

表の作成後に、ALTER TABLE文が発行され、REFに対するSCOPE FOR制約が追加されます。REFに対するSCOPE FOR制約は、CREATE TABLE文では指定できません。Stock_refで参照できるのがオブジェクト表Stock_objtabのみであることを指定するには、PoLine_ntab記憶表に対して次のALTER TABLE文を発行します。

例A-28 SCOPE FOR制約の追加

ALTER TABLE PoLine_ntab
ADD (SCOPE FOR (Stock_ref) IS stock_objtab) ;

この文では、ネストした表のStock_ref列の有効範囲をStock_objtabに制限するように指定します。これは、この列に格納される値がStock_objtab内の行オブジェクトへの参照である必要があることを示します。参照制約とは異なり、SCOPE制約には参照先オブジェクトへの依存性がありません。たとえば、Stock_objtab内で参照されている行オブジェクトは、ネストした表のStock_ref列で参照されていても削除できます。このような削除により、ネストした表内の対応する参照はDANGLING REFとなります。

図A-5 ネストした表LineItemList_ntabのオブジェクト・リレーショナル表現

Oracleでは、記憶表に対する参照制約の指定はサポートされていません。この場合は、REF列に対するSCOPE句を指定すると有効です。通常、REF列に対して有効範囲または参照制約を指定すると、次のようなメリットがあります。

- Oracleで行オブジェクトの一意識別子のみを列にREF値として格納できるため、記憶域の節約になります。

- 記憶表のREF列に索引を作成できます。

- Oracleでは、これらのREFの参照解除を含む問合せを、参照表が関係する結合としてリライトできます。

この時点で、発注書アプリケーションのすべての表が作成されました。次の項では、これらの表の操作方法について説明します。

図A-6 表PurchaseOrder_objtabのオブジェクト・リレーショナル表現

値の挿入

ここでは、前にリレーショナル表に挿入したのと同じデータをオブジェクト表に挿入する方法について説明します。型のインスタンスを作成するために、一部の値によりオブジェクト型のコンストラクタへのコールが取り込まれていることに注意してください。

例A-29 Stock_objtabへの値の挿入

INSERT INTO Stock_objtab VALUES(1004, 6750.00, 2) ;
INSERT INTO Stock_objtab VALUES(1011, 4500.23, 2) ;
INSERT INTO Stock_objtab VALUES(1534, 2234.00, 2) ;
INSERT INTO Stock_objtab VALUES(1535, 3456.23, 2) ;

例A-30 Customer_objtabへの値の挿入

INSERT INTO Customer_objtab
VALUES (
1, 'Jean Nance',
Address_objtyp('2 Avocet Drive', 'Redwood Shores', 'CA', '95054'),
PhoneList_vartyp('415-555-0102')
) ;

INSERT INTO Customer_objtab
VALUES (
2, 'John Nike',
Address_objtyp('323 College Drive', 'Edison', 'NJ', '08820'),
PhoneList_vartyp('609-555-0190','201-555-0140')
) ;

例A-31 PurchaseOrder_objtabへの値の挿入

INSERT INTO PurchaseOrder_objtab
SELECT  1001, REF(C),
SYSDATE, '10-MAY-1999',
LineItemList_ntabtyp(),
NULL
FROM   Customer_objtab C
WHERE  C.CustNo = 1 ;

この文では、次の属性を持つPurchaseOrder_objtypオブジェクトが構成されます。

PONo 1001
Cust_ref REF to customer number 1
OrderDate SYSDATE
ShipDate 10-MAY-1999
LineItemList_ntab an empty LineItem_ntabtyp
ShipToAddr_obj NULL

この文では、問合せを使用して、CustNo値が1であるCustomer_objtabオブジェクト表の行オブジェクトへのREFが構成されます。

次の文では、TABLE式を使用して、ネストした表が挿入先として識別されます。これは、PONo値が1001であるPurchaseOrder_objtab表の行オブジェクトのLineItemList_ntab列にあるネストした表です。

例A-32 LineItemList_ntabへの値の挿入

INSERT INTO TABLE (
SELECT  P.LineItemList_ntab
FROM   PurchaseOrder_objtab P
WHERE  P.PONo = 1001
)
SELECT  01, REF(S), 12, 0
FROM   Stock_objtab S
WHERE  S.StockNo = 1534 ;

この文では、TABLE式で識別されたネストした表に明細項目が1つ挿入されます。挿入される明細項目には、Stock_objtabオブジェクト表内でStockNo値が1534の行オブジェクトへのREFが含まれています。

次の文は、前述の文と同じパターンに従います。

例A-33 PurchaseOrder_objtabおよびLineItemList_ntabへの値の挿入

INSERT INTO PurchaseOrder_objtab
SELECT  2001, REF(C),
SYSDATE, '20-MAY-1997',
LineItemList_ntabtyp(),
Address_objtyp('55 Madison Ave','Madison','WI','53715')
FROM   Customer_objtab C
WHERE  C.CustNo = 2 ;

INSERT INTO TABLE (
SELECT  P.LineItemList_ntab
FROM   PurchaseOrder_objtab P
WHERE  P.PONo = 1001
)
SELECT  02, REF(S), 10, 10
FROM   Stock_objtab S
WHERE  S.StockNo = 1535 ;

INSERT INTO TABLE (
SELECT  P.LineItemList_ntab
FROM   PurchaseOrder_objtab P
WHERE  P.PONo = 2001
)
SELECT  10, REF(S), 1, 0
FROM   Stock_objtab S
WHERE  S.StockNo = 1004 ;

INSERT INTO TABLE (
SELECT  P.LineItemList_ntab
FROM   PurchaseOrder_objtab P
WHERE  P.PONo = 2001
)
VALUES(11, (SELECT REF(S)
FROM  Stock_objtab S
WHERE S.StockNo = 1011), 2, 1) ;

問合せ

次の問合せ文は、暗黙的に比較メソッドを起動します。この例は、OracleでPurchaseOrder_objtyp型のオブジェクトがその型の比較メソッドを使用して順序付けされる方法を示しています。

例A-34 発注書の問合せ

SELECT  p.PONo
FROM   PurchaseOrder_objtab p
ORDER BY VALUE(p) ;

Oracleは、選択されたPurchaseOrder_objtypオブジェクトごとにマップ・メソッドgetPONoを起動します。このメソッドはオブジェクトのPONo属性を戻すため、選択により発注書番号の昇順リストが生成されます。

次の問合せは、リレーショナル・モデルに基づいて実行された問合せに対応します。

例A-35 発注書1001の顧客および明細項目データの問合せ

SELECT  DEREF(p.Cust_ref), p.ShipToAddr_obj, p.PONo,
p.OrderDate, LineItemList_ntab
FROM   PurchaseOrder_objtab p
WHERE  p.PONo = 1001 ;

例A-36 各発注書の合計値の問合せ

SELECT   p.PONo, p.sumLineItems()
FROM    PurchaseOrder_objtab p ;

例A-37 在庫品目1004に関する発注書および明細項目データの問合せ

SELECT   po.PONo, po.Cust_ref.CustNo,
CURSOR (
SELECT  *
FROM   TABLE (po.LineItemList_ntab) L
WHERE  L.Stock_ref.StockNo = 1004
)
FROM    PurchaseOrder_objtab po ;

前述の問合せでは、ネストした表から選択されたLineItem_objオブジェクトのセットについてネストしたカーソルが戻されます。アプリケーションでは、ネストしたカーソルからフェッチして個別のLineItem_objオブジェクトを取得できます。この問合せは、ネストしたセットを外側の結果からネスト解除して表すこともできます。

SELECT   po.PONo, po.Cust_ref.CustNo, L.*
FROM    PurchaseOrder_objtab po, TABLE (po.LineItemList_ntab) L
WHERE   L.Stock_ref.StockNo = 1004 ;

前述の問合せでは、結果セットが平滑化された形式(第1標準形式)で戻されます。このタイプの問合せは、リレーショナル・ツールやODBCなどのAPIからOracleコレクション列にアクセスする際に役立ちます。前述のネスト解除例では、LineItemList_ntab行を持つPurchaseOrder_objtabオブジェクト表の行のみが戻されます。対応するLineItemList_ntab内の行の有無に関係なくPurchaseOrder_objtab表の行をすべてフェッチするには、(+)演算子が必要です。

SELECT   po.PONo, po.Cust_ref.CustNo, L.*
FROM    PurchaseOrder_objtab po, TABLE (po.LineItemList_ntab) (+) L
WHERE   L.Stock_ref.StockNo = 1004 ;

例A-38の要求では、すべてのPurchaseOrder_objtab行のすべてのネストした表LineItemList_ntabの行を問い合せる必要があります。ネスト解除も必要です。

例A-38 すべての発注書のすべての明細項目の平均値引の問合せ

SELECT AVG(L.DISCOUNT)
FROM PurchaseOrder_objtab po, TABLE (po.LineItemList_ntab) L ;

削除

次の例には、例A-13に示したリレーショナル・モデルの場合に必要だった2つの削除と同じ効果があります。例A-39では、明細項目を含めて発注書オブジェクト全体が1回のSQL操作で削除されます。リレーショナル・モデルの場合は、発注書の明細項目を明細項目表から削除し、発注書を発注書表から個別に削除する必要があります。

注意:
このサンプルのSQL文を実行する場合、発注書は以降の例に必要になるため、例A-39のDELETE文を実行しないでください。

例A-39 オブジェクト・リレーショナル・モデルに基づく発注書1001の削除

DELETE
FROM   PurchaseOrder_objtab
WHERE  PONo = 1001 ;

オブジェクト型の進化

完成して完全にビルドされたアプリケーションであっても、未完成となる傾向があります。要件が変化したり、基礎となるオブジェクト・モデルやスキーマを新しい状況にあわせて変更せざるを得なくなったり、当初意図していたものよりも適切にジョブを実行するためにオブジェクト・モデルを改良する方法があったりする場合があります。

オブジェクト・リレーショナル・アプリケーションの運用開始後しばらくして、設計を改良する方法が明らかになったとします。特に、ユーザーは顧客レコードを表示するときに、ほぼ常に購入履歴を確認しようとすることが判明したとします。これを現行のオブジェクト・モデルで実行するには、顧客情報と発注書情報が保持される2つの表Customer_objtabおよびPurchaseOrder_objtabの結合が必要です。そこで、関連発注書に関するデータに顧客表から直接アクセスできるように設計を改良することになったとします。

その方法の1つは、顧客の発注書情報がその顧客を表すオブジェクト・インスタンスに適切に組み込まれるように、Customer_objtypを変更することです。つまり、発注書情報の属性をCustomer_objtypに追加する必要があります。複数の発注書に関する情報を保持するには、属性をコレクション型(ネストした表)にする必要があります。

属性の追加は、オブジェクト型を変更または進化させる方法の1つです。型を進化させると、Oracleでは変更内容が型自体およびすべての依存スキーマ・オブジェクト(型のサブタイプ、変更された型を属性として持つ他のオブジェクト型および変更された型の表と列)に適用されます。

Customer_objtypを変更して発注書のネストした表の属性を追加するには、次のように複数の手順が必要です。

1. 発注書のネストした表に使用する新規の型を作成します。

2. Customer_objtypを変更して新規の型の新規の属性を追加します。

3. Customer_objtabオブジェクト表で、新規に追加したネストした表の記憶表の名前と有効範囲を指定します。

- 新規の属性にあわせてCustomer_objtabオブジェクト表をアップグレードすると、発注書自体に明細項目のネストした表が含まれるため、一方の内側に他方が含まれる2レベルのネストした表が実際に追加されます。

- 発注書のネストした表と明細項目のネストした表の両方に主キー・ベースのREFを使用できるように、両方について有効範囲を指定する必要があります。この詳細は、次の項を参照してください。

図A-7 顧客オブジェクト型のネストした表

前述の手順を完了すると、モデルにおける顧客情報と発注書情報の論理的な関連性が明確になり、顧客、発注書および明細項目に関するすべての情報について顧客表を問合せできるようになります。また、顧客表に対する1つのINSERT文で新規顧客の新規発注書を挿入できます。

Customer型への属性の追加

発注書のネストした表をCustomer_objtypの属性として追加する前に、この種のネストした表の型を定義する必要があります。そのためには次の文を使用します。

例A-40 PurchaseOrderList_ntabtypの作成

CREATE TYPE PurchaseOrderList_ntabtyp AS TABLE OF PurchaseOrder_objtyp;
/

これで、ALTER TYPE文を使用して、この型の属性をCustomer_objtypに追加できます。

例A-41 Customer_objtypの変更

ALTER TYPE Customer_objtyp
ADD ATTRIBUTE (PurchaseOrderList_ntab PurchaseOrderList_ntabtyp)
CASCADE;

変更する型に依存型または依存表がある場合は、型に対するALTER TYPE文でCASCADEまたはINVALIDATEを指定して、依存オブジェクトに対する変更内容の適用方法を指定する必要があります。

- CASCADEを指定すると、型変更の適用前に依存オブジェクトの妥当性チェックが実行されます。これらのチェックでは、変更により、表のパーティション・キーとして使用中の属性が削除されるなどの不正動作が発生しないことが確認されます。依存オブジェクトが検証に失敗すると、型の変更は異常終了します。これに対して、すべての依存オブジェクトが検証に成功すると、システムは型の変更を伝播するために必要なメタデータおよびデータの変更に進みます。これには、列の追加と削除、ネストした表の記憶表の作成などが自動的に含まれる場合があります。

- INVALIDATEオプションを指定すると、予備的な妥当性チェックはスキップされ、型の変更が依存オブジェクトに直接適用されます。それらのオブジェクトは、次回のアクセス時に検証されます。このようにして型を変更すると検証所要時間が短縮されますが、後にユーザーがアクセスを試行した依存表を検証できない場合は、表が検証に合格するまでそのデータにアクセスできなくなります。

Customer_objtab表に追加される発注書と明細項目の新規のネストした表ごとに、REF列の有効範囲を追加する必要があります。便宜上、まず新規の表の名前をシステム生成名から認識可能な名前に変更します。次に、指定した名前を使用して記憶表を変更し、そのREF列の有効範囲を追加できます。

この操作を実行する必要があるのは、主キー・ベースのオブジェクト識別子を持つ表の列にオブジェクトへのREFを格納するには、列の有効範囲としてその表を指定するか、参照制約を適用する必要があるためです。列の有効範囲を特定の表に制限するには、その列のすべてのREFがその表のオブジェクトへのREFであると宣言します。この宣言が必要となるのは、主キー・ベースのオブジェクト識別子の一意性が保証されるのが特定の表のコンテキスト内のみであり、すべての表にまたがって一意であるとはかぎらないためです。主キー・ベースのREFまたはユーザー定義REFを有効範囲なしの列に挿入しようとすると、次のようなエラーが戻されます。

オブジェクト・ビューREFまたはユーザー定義REFを挿入できません。

明細項目には、オブジェクト識別子に表の主キーが使用されているStock_objtab表内のオブジェクトへのREFが含まれます。このため、PurchaseOrder_objtab表を作成した後で、その表内の明細項目のネストした表の記憶表にREF列の有効範囲を追加する必要がありました。次に、これと同じ操作を表Customer_objtab内の明細項目の新規のネストした表について実行する必要があります。

さらに、Customer_objtab表に追加する発注書の新規のネストした表について、同じ操作を実行する必要があります。発注書ではCustomer_objtab表の顧客が参照され、この表のオブジェクト識別子も主キー・ベースです。

次の文を使用して、名前を変更できるようにシステム生成表の名前を確認します。

SELECT table_name, parent_table_name, parent_table_column FROM user_nested_tables;

出力は次のようになります。

TABLE_NAME                    PARENT_TABLE_NAME             PARENT_TABLE_COLUMN
----------------------------- ----------------------------- ----------------------
SYSNTQOFArJyBTHu6iOMMKU4wHw== CUSTOMER_OBJTAB               PURCHASEORDERLIST_NTAB
POLINE_NTAB                   PURCHASEORDER_OBJTAB          LINEITEMLIST_NTAB
SYSNTZqu6IQItR++UAtgz1rMB8A== SYSNTQOFArJyBTHu6iOMMKU4wHw== LINEITEMLIST_NTAB

便宜上、システム生成のネストした表を適切な名前に変更します。たとえば、前述のサンプル出力のシステム生成名を使用して、次のように変更します。

ALTER TABLE "SYSNTQOFArJyBTHu6iOMMKU4wHw==" RENAME TO PO_List_nt;
ALTER TABLE "SYSNTZqu6IQItR++UAtgz1rMB8A==" RENAME TO Items_List_nt;

システム生成のネストした表の名前を変更するプロセスは、次のPL/SQLプロシージャを使用して自動的に実行することもできます。

DECLARE
nested_table_1 VARCHAR2(30);
nested_table_2 VARCHAR2(30);
cust_obj_table VARCHAR2(30) := 'CUSTOMER_OBJTAB';
BEGIN
EXECUTE IMMEDIATE ' SELECT table_name FROM user_nested_tables
WHERE parent_table_name = :1 ' INTO nested_table_1 USING cust_obj_table;
EXECUTE IMMEDIATE ' SELECT table_name FROM user_nested_tables
WHERE parent_table_name = :1 ' INTO nested_table_2 USING nested_table_1;
EXECUTE IMMEDIATE 'ALTER table "'|| nested_table_1 ||'" RENAME TO PO_List_nt';
EXECUTE IMMEDIATE 'ALTER table "'|| nested_table_2 ||'" RENAME TO Items_List_nt';
END;
/

新規の記憶表の名前はPO_List_ntおよびItems_List_ntです。次の文では、この2つの表のREF列の有効範囲を特定の表に限定します。

例A-42 ネストした表へのREFの有効範囲の追加

ALTER TABLE PO_List_nt ADD (SCOPE FOR (Cust_Ref) IS Customer_objtab);
ALTER TABLE Items_List_nt ADD (SCOPE FOR (Stock_ref) IS Stock_objtab);

Customer_objtabに顧客の発注書を挿入する前に、もう1つ必要な操作があります。PurchaseOrderList_ntabtypの実際のネストした表を、表内の顧客ごとにインスタンス化する必要があります。

新規の属性に関する列が表に追加されると、既存の行の列値がNULLに初期化されます。これは、既存の各顧客のネストした発注書表がアトミックNULLに設定されること(そこには実際にネストした表は存在せず、空の表もないこと)を意味します。顧客ごとにネストした表をインスタンス化するまでは、発注書を挿入しようとすると次のようなエラーが戻されます。

NULLの表値を参照しています。

次の文では、実際のネストした表のインスタンスを含むように各行を更新して、発注書を保持する列を準備します。

例A-43 Customer_objtabの更新

UPDATE Customer_objtab c
SET c.PurchaseOrderList_ntab = PurchaseOrderList_ntabtyp();

この文で、PurchaseOrderList_ntabtyp()はネストした表の型のコンストラクタ・メソッドへのコールです。このコールでは、発注書は指定されておらず、空のネストした表が作成されます。

マルチレベル・コレクションの操作

この時点までに、Customer_objtyp型を進化させて発注書のネストした表を追加し、ネストした表に発注書を格納できるように表Customer_objtabを設定しました。これで、発注書をCustomer_objtabに挿入する準備が完了したことになります。

表PurchaseOrder_objtabには、すでに2件の発注書があります。次の2つの文では、これらの発注書をCustomer_objtabにコピーします。

例A-44 Customer_objtabへの発注書の挿入

INSERT INTO TABLE (
SELECT   c.PurchaseOrderList_ntab
FROM   Customer_objtab c
WHERE  c.CustNo = 1
)
SELECT VALUE(p)
FROM PurchaseOrder_objtab p
WHERE p.Cust_Ref.CustNo = 1;

INSERT INTO TABLE (
SELECT   c.PurchaseOrderList_ntab
FROM   Customer_objtab c
WHERE  c.CustNo = 2
)
SELECT VALUE(p)
FROM PurchaseOrder_objtab p
WHERE p.Cust_Ref.CustNo = 2;

ネストした表への挿入

前述の各INSERT文には2つの主要部分があります。挿入操作のターゲット表を指定するTABLE式と、挿入するデータを取得するSELECTです。各部分のWHERE句では、発注書を(TABLE式で)受け取る顧客オブジェクトと、発注書の(発注書を取得する副問合せでの)選択対象となる顧客を選択します。

副問合せのWHERE句では、ドット表記法を使用してCustNo属性p.Cust_Ref.CustNoにナビゲートします。ドット表記法を使用する場合は、表の別名pが必須であることに注意してください。別名を省略してかわりにCust_Ref.CustNoを指定すると、エラーになります。

このWHERE句のドット表記法については、発注書のCust_Ref REF属性を介して顧客のCustNo属性にナビゲートできることにも注意する必要があります。PL/SQLではなくSQLは、この方法でドット表記法に使用されているREFを暗黙的に参照解除します。

INSERT文の最初の部分のTABLE式は、式から戻されるコレクションを表として処理するようにシステムに対して指示します。ここでは、式は特定の顧客に関する発注書のネストした表を挿入ターゲットとして選択するために使用されています。

INSERT文の第2の部分では、VALUE()ファンクションが選択した行をオブジェクトとして戻します。この場合、各行は発注書オブジェクトであり、明細項目の固有のコレクションで終了します。発注書の各行は、PurchaseOrder_objtyp型のある表から選択され、その型の別の表に挿入されます。

前述のINSERT文では、PurchaseOrder_objtypの顧客参照属性を使用して、既存の各発注書が属している顧客を識別しています。ただし、この時点で、古い発注書がすべて発注書表からアップグレード後のCustomer_objtabにコピーされ、発注書のこの顧客参照属性は使用されなくなります。これで、発注書は顧客オブジェクト自体に格納されるようになります。

次のALTER TYPE文では、顧客参照属性を削除するためにPurchaseOrder_objtypを進化させます。この文では、出荷先所在地が常に顧客所在地と同一であるとみなし、ShipToAddr_obj属性も冗長として削除します。

例A-45 PurchaseOrder_objtypの変更

ALTER TYPE PurchaseOrder_objtyp
DROP ATTRIBUTE Cust_ref,
DROP ATTRIBUTE ShipToAddr_obj
CASCADE;

この時点で、CASCADEオプションを使用して、システムで検証を実行し、依存型および依存表に対して必要な変更をすべて行えるようになりました。

明細項目を含む新規発注書の挿入

前述したINSERTの例は、VALUE()ファンクションを使用して、既存の発注書オブジェクトを選択し、発注書のネストした表に挿入して、明細項目の固有のネストした表で完了する方法を示していました。次の例は、発注書オブジェクトとしてインスタンス化されていない新規発注書の挿入方法を示しています。この場合、発注書の明細項目のネストした表を、各明細項目オブジェクトおよびデータとともにインスタンス化する必要があります。参照しやすいように明細番号を左側に示してあります。

例A-46 VALUE()を使用したLineItemList_ntabtypへの挿入

INSERT INTO TABLE (                                             /* Line 1  */
SELECT c.PurchaseOrderList_ntab                               /* Line 2  */
FROM Customer_objtab c                                      /* Line 3  */
WHERE c.CustName = 'John Nike'                              /* Line 4  */
)                                                            /* Line 5  */
VALUES (1020, SYSDATE, SYSDATE + 1,                           /* Line 6  */
LineItemList_ntabtyp(                                       /* Line 7  */
LineItem_objtyp(1, MAKE_REF(Stock_objtab, 1004), 1, 0),   /* Line 8  */
LineItem_objtyp(2, MAKE_REF(Stock_objtab, 1011), 3, 5),   /* Line 9  */
LineItem_objtyp(3, MAKE_REF(Stock_objtab, 1535), 2, 10)   /* Line 10 */
)                                                         /* Line 11 */
);                                                              /* Line 12 */

行1から5では、TABLE式を使用して、挿入対象となるネストした表(顧客John Nikeに関する発注書のネストした表など)を選択します。

VALUES句(行6から12)には、次のように新規発注書の各属性の値が含まれています。

PONo
OrderDate
ShipDate
LineItemList_ntab

INSERT文の行6では、3つの発注書属性PONo、OrderDateおよびShipDateの値を指定します。

属性値のみが指定され、発注書コンストラクタは指定されていません。ネストした表は発注書のネストした表として宣言されているため、発注書コンストラクタを明示的に指定して発注書インスタンスをネストした表内でインスタンス化する必要はありません。発注書コンストラクタを省略すると、システムにより自動的に発注書がインスタンス化されます。ただし、必要な場合はコンストラクタを指定でき、その場合、VALUES句は次のようになります。

INSERT INTO TABLE (
SELECT c.PurchaseOrderList_ntab
FROM Customer_objtab c
WHERE c.CustName = 'John Nike'
)
VALUES (
PurchaseOrder_objtyp(1025, SYSDATE, SYSDATE + 1,
LineItemList_ntabtyp(
LineItem_objtyp(1, MAKE_REF(Stock_objtab, 1004), 1, 0),
LineItem_objtyp(2, MAKE_REF(Stock_objtab, 1011), 3, 5),
LineItem_objtyp(3, MAKE_REF(Stock_objtab, 1535), 2, 10)
)
)
)

行7から11では、明細項目のネストした表をインスタンス化してデータを提供します。コンストラクタ・メソッドLineItemList_ntabtyp(…)では、3つの明細項目を含むネストした表のインスタンスを作成します。

明細項目コンストラクタLineItem_objtyp()では、各明細項目のオブジェクト・インスタンスを作成します。明細項目属性の値は、コンストラクタの引数として指定します。

MAKE_REFファンクションでは、明細項目のStock_ref属性のREFを作成します。MAKE_REFの引数は、在庫表の名前と、参照する在庫品目の主キー値です。ここでMAKE_REFを使用できるのは、在庫表内のオブジェクト識別子が主キーに基づいているためです。主キーに基づいていない場合は、副問合せでREFファンクションを使用して在庫表の行へのREFを取得する必要があります。

マルチレベルのネストした表の問合せ

他の(埋込みではなく)トップレベルの列または属性のように、名前をSELECT構文のリストに指定すると、トップレベルのネストした表列を問い合せることができますが、結果はあまり読みやすくありません。たとえば、次の問合せでは、John Nikeに関する発注書のネストした表を選択します。

例A-47 顧客John Nikeに関するCustomer_objtabの問合せ

SELECT c.PurchaseOrderList_ntab
FROM Customer_objtab c
WHERE CustName = 'John Nike';

この問合せでは、次のような結果が生成されます。

PURCHASEORDERLIST_NTAB(PONO, ORDERDATE, SHIPDATE, LINEITEMLIST_NTAB(LINEITEMNO,
--------------------------------------------------------------------------------
PURCHASEORDERLIST_NTABTYP(PURCHASEORDER_OBJTYP(2001, '25-SEP-01', '20-MAY-97', L
INEITEMLIST_NTABTYP(LINEITEM_OBJTYP(10, 00004A038A00468ED552CE6A5803ACE034080020
B8C8340000001426010001000100290000000000090600812A00078401FE0000000B03C20B050000
...

インスタンス・データをネストしていない形式で表示し、REFをまったく表示しない方が読みやすくなります。TABLE式を(この場合は問合せのFROM句に)使用すると、読みやすい形式で表示できます。

たとえば、例A-48の問合せでは、John Nikeに属している全発注書の発注書番号、発注日および出荷日を選択します。

例A-48 TABLE式を使用したCustomer_objtabの問合せ

SELECT p.PONo, p.OrderDate, p.Shipdate
FROM Customer_objtab c, TABLE(c.PurchaseOrderList_ntab) p
WHERE c.CustName = 'John Nike';

PONO ORDERDATE SHIPDATE
------- --------- ---------
2001 25-SEP-01 26-SEP-01
1020 25-SEP-01 26-SEP-01

TABLE式は引数としてコレクションを取り、SQL文のSQL表と同様に使用できます。前述の問合せでは、FROM句のTABLE式に発注書のネストした表をリストすると、通常の表列の場合と同様にネストした表の列を選択できます。各列は、使用する表別名pにより、ネストした表に属する列として識別されます。この例に示すとおり、FROM句のTABLE式にも、式自身の表別名を持たせることが可能です。

TABLE式では、ネストした表は顧客表Customer_objtab自体の表別名cにより、顧客表の列として識別されます。FROM句では、Customer_objtab表がそれを参照するTABLE式の前に指定されていることに注意してください。このように、TABLE式でFROM句の左辺に指定されている表別名を使用する機能を、左相関といいます。これを使用すると、表とTABLE式をデイジー・チェーン化できます(これには、別のTABLE式の表別名を使用するTABLE式が含まれます)。実際には、この方法を使用して、他のネストした表に埋め込まれているネストした表の列を選択できます。

たとえば、次の例に発注書番号1020に関するすべての明細項目情報を選択する問合せを示します。

例A-49 発注書1020に関するCustomer_objtabの問合せ

SELECT p.PONo, i.LineItemNo, i.Stock_ref.StockNo, i.Quantity, i.Discount
FROM Customer_objtab c, TABLE(c.PurchaseOrderList_ntab) p,
TABLE(p.LineItemList_ntab) i
WHERE p.PONo = 1020;

PONO LINEITEMNO STOCK_REF.STOCKNO QUANTITY DISCOUNT
----- ---------- ----------------- ---------- ----------
1020 1 1004 1 0
1020 2 1011 3 5
1020 3 1535 2 10

この問合せでは2つのTABLE式を使用し、第2の式で第1の式を参照しています。明細項目情報は、外側のネストした表内の発注書番号1020に属している内側のネストした表から選択されます。

顧客表の列は、SELECT構文のリストにもWHERE句にも指定されていないことに注意してください。顧客表は、ネストした表へのアクセス開始点を指定するためにのみFROM句に指定されています。

次に前述の問合せのバリエーションを示します。このバージョンは、ワイルド・カード*を使用してTABLE式のコレクションの列をすべて指定できることを示しています。

SELECT p.PONo, i.*
FROM Customer_objtab c, TABLE(c.PurchaseOrderList_ntab) p,
TABLE(p.LineItemList_ntab) i
WHERE p.PONo = 1020;

型の継承と代入可能な列

会計マネージャを介して大口の標準顧客を多数処理するとします。会計マネージャのIDに使用するフィールドを、これらの顧客の顧客レコードに追加する必要があります。

前述の例では、発注書のネストした表の属性を追加する必要が生じたときに、顧客の型自体を進化させました。会計マネージャIDの属性を追加する際には、前回と同様の方法を使用するか、顧客型のサブタイプを作成し、サブタイプにのみ属性を追加できます。どちらの方法を使用するのが適切であるかを考えてみます。

この種の決定を行うには、提示された新規属性をベース型のすべてのインスタンス(すべての顧客)に有意かつ有効に適用できるか、またはベース型で識別可能なサブクラスにのみ適用できるかを検討する必要があります。

前述の例では、すべての顧客が発注書を持っているため、型自体を変更してその属性を追加する方法が適切でした。ただし、すべての顧客に会計マネージャがいるとはかぎらず、実際に会計マネージャがいるのは法人顧客のみです。そのため、顧客型を進化させて一般顧客には意味のない属性を追加するかわりに、識別した特殊な種類の顧客用に新規のサブタイプを作成し、そこに新規の属性を追加する方が適切です。

サブタイプの作成

ベース型に基づいてサブタイプを作成できるのは、ベース型でサブタイプが許可されている場合のみです。型のサブタイプを作成できるかどうかは、その型のFINALプロパティに応じて異なります。デフォルトでは、新規の型はFINALとして作成されます。これは、それがシリーズの最後の型であり、サブタイプを作成できないことを意味します。サブタイプを作成できる型を作成するには、顧客型を作成したときと同様にCREATE TYPE文でNOT FINALを指定する必要があります。

サブタイプを定義するには、CREATE TYPE文でUNDERキーワードを使用します。次の文では、Customer_objtypに新規のサブタイプCorp_Customer_objtypを作成します。この型はNOT FINALとして作成されるため、後で追加が必要になった場合にサブタイプを持たせることができます。

例A-50 Corp_Customer_objtypの作成

CREATE TYPE Corp_Customer_objtyp UNDER Customer_objtyp
(account_mgr_id     NUMBER(6) ) NOT FINAL;
/

CREATE TYPE文を使用して新規サブタイプを作成する際には、新規に追加する属性およびメソッドのみを指定します。サブタイプはベース型から既存の属性とメソッドをすべて継承するため、指定する必要はありません。新規の属性およびメソッドは、継承された属性およびメソッドの後に追加されます。たとえば、新規Corp_Customer_objtypサブタイプの属性の完全リストは次のようになります。

CustNo
CustName
Address_obj
Phonelist_var
PurchaseOrderList_ntab
Account_mgr_id

デフォルトでは、サブタイプのインスタンスは、対応する任意のベース型の任意の列またはオブジェクト表に格納できます。このように、ベース型のスロットにサブタイプのインスタンスを格納する機能を、代入性といいます。列と表は、明示的にNOT SUBSTITUTABLEとして宣言されていないかぎり代入可能です。サブタイプ属性用の新規列と、各行に格納されるインスタンスの型ID用の非表示列が、システムにより自動的に追加されます。

実際には、FINAL型のサブタイプを作成できますが、最初にALTER TYPE文を使用して型をFINAL型からNOT FINAL型に進化させておく必要があります。変更した型の既存の列および表に新規サブタイプのインスタンスを格納可能にするには、ALTER TYPE文でCASCADEオプションCONVERT TO SUBSTITUTABLEを指定します。「型進化」を参照してください。

サブタイプの挿入

列またはオブジェクト表が代入可能な場合は、その列または表の宣言された型のインスタンスのみでなく、宣言された型の任意のサブタイプのインスタンスも挿入できます。Customer_objtab表の場合、これは表を使用してあらゆる種類(標準と法人の両方)の顧客に関する情報を格納できることを意味します。ただし、サブタイプの場合、情報の挿入方法には1つ重要な違いがあります。つまり、サブタイプのコンストラクタを明示的に指定する必要があります。コンストラクタの使用がオプションとなるのは、列または表の宣言された型のインスタンスの場合のみです。

たとえば、次の文では新規の標準顧客William Kiddを挿入します。

例A-51 標準顧客に関するデータの挿入

INSERT INTO Customer_objtab
VALUES (
3, 'William Kidd',
Address_objtyp('43 Harbor Drive', 'Redwood Shores', 'CA', '95054'),
PhoneList_vartyp('650-555-0188'),
PurchaseOrderList_ntabtyp()
);

VALUES句には各Customer_objtyp属性のデータが含まれていますが、Customer_objtypコンストラクタは省略されています。ここでコンストラクタがオプションなのは、表の宣言された型がCustomer_objtypであるためです。ネストした表の属性の場合、コンストラクタPurchaseOrderList_ntabtyp()では空のネストした表が作成されますが、発注書のデータは指定されていません。

次の例に、同じ表に新規の法人顧客を挿入する文を示します。コンストラクタCorp_Customer_objtyp()が使用され、会計マネージャIDのデータ値531が指定されていることに注意してください。

例A-52 法人顧客に関するデータの挿入

INSERT INTO Customer_objtab
VALUES (
Corp_Customer_objtyp(   -- Subtype requires a constructor
4, 'Edward Teach',
Address_objtyp('65 Marina Blvd', 'San Francisco', 'CA', '94777'),
PhoneList_vartyp('415-555-0198', '415-555-0199'),
PurchaseOrderList_ntabtyp(), 531
)
);

次の文では、2つの新規顧客それぞれについて1件の発注書を挿入します。新規顧客を挿入する文とは異なり、発注書を挿入する2つの文の構造は同じですが、発注書の明細項目数が異なっています。

例A-53 標準顧客に関する発注書の挿入

INSERT INTO TABLE (
SELECT c.PurchaseOrderList_ntab
FROM Customer_objtab c
WHERE c.CustName = 'William Kidd'
)
VALUES (1021, SYSDATE, SYSDATE + 1,
LineItemList_ntabtyp(
LineItem_objtyp(1, MAKE_REF(Stock_objtab, 1535), 2, 10),
LineItem_objtyp(2, MAKE_REF(Stock_objtab, 1534), 1, 0)
)
);

例A-54 法人顧客に関する発注書の挿入

INSERT INTO TABLE (
SELECT c.PurchaseOrderList_ntab
FROM Customer_objtab c
WHERE c.CustName = 'Edward Teach'
)
VALUES (1022, SYSDATE, SYSDATE + 1,
LineItemList_ntabtyp(
LineItem_objtyp(1, MAKE_REF(Stock_objtab, 1011), 1, 0),
LineItem_objtyp(2, MAKE_REF(Stock_objtab, 1004), 3, 0),
LineItem_objtyp(3, MAKE_REF(Stock_objtab, 1534), 2, 0)
)
);

代入可能な列の問合せ

代入可能な列または表には、複数のデータ型のデータを含めることができます。これにより、たとえば顧客表の1回の問合せで全種類の顧客に関する情報を取得できます。ただし、特定の種類の顧客に関する情報のみ、またはその顧客の特定の属性に関する情報のみを取得することもできます。

次の例に、代入可能な表または列から必要な情報を取得する際に役立つ方法をいくつか示します。

例A-55に示す問合せでは、IS OF条件を含むWHERE句を使用して、ある種の法人顧客でない顧客を除外します。つまり、この問合せでは、法人顧客はすべて戻されますが、他の種類の顧客のインスタンスは戻されません。

例A-55 すべての法人顧客とそのサブタイプの選択

SELECT c.*
FROM Customer_objtab c
WHERE VALUE(c) IS OF (Corp_Customer_objtyp);

例A-56に示す問合せは前述の例と似ていますが、Corp_Customer_objtypのサブタイプを除外するためにIS OF条件にONLYキーワードが追加されています。最も限定的な型がCorp_Customer_objtypであるインスタンスの行のみが戻されます。

例A-56 サブタイプのないすべての法人顧客の選択

SELECT p.PONo
FROM Customer_objtab c, TABLE(c.PurchaseOrderList_ntab) p
WHERE VALUE(c) IS OF (ONLY Corp_Customer_objtyp);

例A-57に示す問合せでは、TABLE式を使用して発注書番号を(発注書のネストした表から)取得します。全種類の顧客がこの属性を持っていますが、WHERE句により検索対象が法人顧客のみに限定されています。

例A-57 法人顧客のみの発注書番号の選択

SELECT p.PONo
FROM Customer_objtab c, TABLE(c.PurchaseOrderList_ntab) p
WHERE VALUE(c) IS OF (Corp_Customer_objtyp);

例A-58に示す問合せでは、会計マネージャIDのデータが戻されます。これは法人顧客サブタイプでのみ保持される属性であり、表の宣言された型には欠落しています。問合せでは、サブタイプ属性Account_mgr_idにアクセスするために、TREAT()ファンクションを使用して各顧客を法人顧客として処理させています。

例A-58 TREATファンクションを使用したサブタイプ属性の選択

SELECT CustName, TREAT(VALUE(c) AS Corp_Customer_objtyp).Account_mgr_id
FROM Customer_objtab c
WHERE VALUE(c) IS OF (ONLY Corp_Customer_objtyp);

例A-58でTREAT()が必要なのは、Account_mgr_idが表の宣言された型Customer_objtypの属性ではないためです。前述のように属性をSELECT構文のリストで指定するのみの場合、例A-59のような問合せでは「無効な列名」というエラーが戻されます。これは、Corp_Customer_objtypのインスタンスを除く全インスタンスを除外するWHERE句を使用した場合も同じです。WHERE句は結果から行を除外するのみであるため、ここでは不十分です。

例A-59 TREATファンクションを使用しないサブタイプ属性の選択

-- Following statement returns error, invalid column name for Account_mgr_id
SELECT CustName, Account_mgr_id
FROM Customer_objtab c
WHERE VALUE(c) IS OF (ONLY Corp_Customer_objtyp);

代入可能な各列またはオブジェクト表には、各行のインスタンスの型を識別する非表示の型ID列が関連付けられています。型の型IDは、USER_TYPESカタログ・ビューで確認できます。

ファンクションSYS_TYPEID()は、特定のインスタンスの型IDを戻します。例A-60に示す問合せでは、USER_TYPESカタログ・ビューでSYS_TYPEID()および結合を使用して、表Customer_objtab内の各顧客インスタンスの型名を戻します。

例A-60 各インスタンスの型の検出

SELECT c.CustName, u.TYPE_NAME
FROM Customer_objtab c, USER_TYPES u
WHERE SYS_TYPEID(VALUE(c)) = u.TYPEID;

--------------------------------- ---------------------
Jean Nance CUSTOMER_OBJTYP
John Nike CUSTOMER_OBJTYP
William Kidd CUSTOMER_OBJTYP
Edward Teach CORP_CUSTOMER_OBJTYP

SYS_TYPEID()、VALUE()およびTREAT()の詳細は、「オブジェクトに便利なファンクションおよび演算子」を参照してください。

用語集

アトミックNULLオブジェクト

自分自身の値がNULLであるオブジェクトを、アトミックNULLといいます。アトミックNULLオブジェクトは、すべての属性の値がNULL値であるオブジェクトとは異なります。

バイナリ・ラージ・オブジェクト(BLOB)

値がRAWバイナリ・データで構成されるラージ・オブジェクト・データ型。

キャラクタ・ラージ・オブジェクト(CLOB)

値がデータベース・キャラクタ・セットに対応する文字データで構成されるラージ・オブジェクト(LOB)データ型。

列オブジェクト

(オブジェクト表ではなく)リレーショナル・データベース表の列として格納されるオブジェクト。列オブジェクトは別のオブジェクトの属性になることもできます。格納されたインライン・オブジェクトまたは埋込みオブジェクトとも呼ばれます。

埋込みオブジェクト属性

列オブジェクトの属性。

動的メソッド・ディスパッチ

オーバーライドを使用する同じメソッドの実装が複数存在する場合に、メソッド・コールが実行時に最も近いメソッド実装にディスパッチされること。

索引構成表(IOT)

索引により編成された表。

リーフ・レベル・スカラー・オブジェクト

コレクションではなく、かつ他の型で構成されていないオブジェクト。

リーフ・レベル・スカラー属性

リーフ・レベル・スカラー・オブジェクトの属性。

リテラル起動

すべての引数がリテラルまたはリテラル・メソッド起動である起動。引数は変数にできない。

マテリアライズド・ビュー

問合せとその結果の両方が含まれるビュー。

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

要素が直接的または間接的にコレクション型であるコレクション型。

多重集合演算子

2つのネストした表の要素を結合して1つのネストした表にする演算子。

ネストした表

同じデータ型の、順序付けられていないデータ要素のセット。

正規化

データを複数の表に分割することでデータの冗長性をなくすプロセス。

オブジェクト列

ユーザー定義型または抽象データ型(ADT)の列。

オブジェクト識別子

行オブジェクトの識別子。システム生成のもの(デフォルト)と、CREATE TABLE文で指定された主キー・ベースのものがあります。

オブジェクト・インスタンス

オブジェクト型のインスタンス。オブジェクトとも呼ばれます。

オブジェクト表

各行がオブジェクトを表している表。「行オブジェクト」を参照してください。

オブジェクト型

オブジェクト・インスタンスの型。メソッドを持つレコードと似ています。ユーザーにより定義されます。

外部表

ネストした表が含まれる表。

確保

フェッチすること。

PL/SQL

OracleがSQLを手続き型言語に拡張したもの。

ポリモフィズム

総じて同じインタフェースを使用するデータ型とメソッドの取扱いを可能にします。ポリモフィックなオーバーライドにおいては、サブタイプは継承したメソッドを再定義します。ポリモフィックなオーバーロードにおいては、異なるパラメータを持つ同じメソッドのバージョンが複数存在することがあります。

主キー

表のPRIMARY KEY制約で指定された列または列セット。

REF

指定されたオブジェクト型の行オブジェクトの参照をカプセル化するOracleの組込みデータ型。

行オブジェクト

オブジェクト表の完全な行に格納されたオブジェクト。

特化

親のスーパータイプが持たない新しい属性またはメソッドをサブタイプに追加したり、メソッドの実装を変更すること。

ストアド・プロシージャ

データベースに格納された、アプリケーションから実行可能なPL/SQLブロック。

代入性

宣言された型がスーパータイプである変数または列に、スーパータイプの下位のサブタイプの1つが使用できる場合、スーパータイプは代入可能です。

型進化

型のサブタイプの変更。通常はALTER文を使用して行われます。

VARRAY

同じデータ型または宣言されたデータ型のサブタイプからなる、順序付けられたデータ要素のセット。

索引
A  B  C  D  E  F  G  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X

A

Active Server Pages, 4.7

ActiveX, 4.7

Admin Option

EXECUTE ANY TYPE, 7.1.3

集計ファンクション

「ユーザー定義集計ファンクション」を参照

別名

表に必要, 2.1.7.1

ALTER ANY TYPE権限, 7.1.1

「権限」も参照

ALTER TABLE, 8.3.9

「オブジェクト型」, 「進化」も参照

ALTER TYPE文, 4.8.5.4, 8.3.8

「オブジェクト型」, 「進化」も参照

ANYDATAデータ型, 8.5, 9.12.2 ANYDATASETデータ型, 8.5 ANYTYPEデータ型, 8.5 配列, A.3.6

VARRAYのサイズ, 5.1.4

ASP, 4.7 代入

オブジェクト型全体, 2.3.15

コレクション, 2.3.15.3

オブジェクトおよびオブジェクトのREF, 2.3.15.1

アトミックNULL, 2.1.1

PL/SQLのオブジェクト型, 3.1.3

属性値コンストラクタ, 2.2.3 属性

リーフ・レベル, 2.1.4, 8.1.1

変更, 8.3.6

オブジェクト型, 1.3.1.1

B

バインド変数

オブジェクト型, 4.3

BULK COLLECT句, 5.3.3

C

キャッシュ

オブジェクト・キャッシュ, 4.4, 4.5, 6.3, 7.1.5

オブジェクト・ビュー, 6.3

取得回避規則, 2.1.7.1 CARDINALITYファンクション, 5.3.5.1 CASTファンクション, 2.4.1 文字長セマンティクス

オブジェクト型, 2.1.2

COLLECTファンクション, 5.3.5.2 コレクション

代入, 2.3.15.3

代入, 5.2

作成, 1.3.1.7

コンストラクタ・メソッド, 5.1.3

作成, 5.1.2

データ型

DML, 5.3.2

マルチレベル, 5.2, 9.4.1

作成, 5.2.3

作成, 5.2.3

REFによる作成, 9.4.5

格納されているオブジェクト・ビュー, 6.6.2

ネストした表, 5.1.5 問合せ, 5.3.1, 9.4.1 「VARRAY」, 「ネストした表」も参照 代入可能な要素, 2.3.8.4 代入 サポートされているデータ型, 1.3.1.7 可変配列(VARRAY), 5.1.4 列オブジェクト, 1.3.1.4

索引, 2.1.4

行オブジェクト, 9.1.1

COLUMN_VALUEキーワード, 5.2.1 列

列オブジェクト, 1.3.1.4

非表示, 8.1.3, 8.2.1

問合せでの修飾, 2.1.7

比較

メソッド, 2.2.1.2, A.3.1, A.3.6.4

ネストした表, 5.3.4

コンパイル

オブジェクト型, 7.2.1

完全型, A.3.1 COMPRESS句

ネストした表, 9.4.4.1

制約, A.3.4

オブジェクト表, 2.1.3

Oracleオブジェクト, 9.9

REF, 9.3.2

SCOPE FOR制約, A.3.6.2

コンストラクタ・メソッド, 5.1.3 コンストラクタ, 1.3.1.3, 2.2.3, 8.1.2

属性値, 8.4.1

ユーザー定義のコール, 8.4.6

リテラル起動, 2.2.3

リテラル起動, 2.2.3

メソッド, 2.2.3

オーバーロード, 8.4.4

オーバーライド, 8.4.4

システム定義, 8.4.1

型進化, 8.4.2

ユーザー定義, 8.4.3, 8.4.4

NEWキーワード, 8.4.1

コレクション型のCOUNT属性, A.3.2.2 CREATE INDEX文

オブジェクト型, 2.1.4

CREATE OR REPLACE TYPE表の依存性, 7.2.4 FORCEオプションを指定したCREATE OR REPLACE TYPE, 7.2.4 表の依存性があるCREATE OR REPLACE TYPE, 7.2.4 CREATE TABLE文

列オブジェクトの例, 1.3.1.2

オブジェクト表の例, 1.3.1.4, 2.1.3

CREATE TRIGGER文

オブジェクト表の例, 2.1.5

CREATE TYPE権限, 7.1.1

「権限」も参照

CREATE TYPE文, 9.12.4.5

コレクション型, 1.3.1.7

依存型, 7.2.1

例, 5.1.5

ネストした表, 5.1.5

オブジェクト型, 1.3.1.1, 1.3.1.1, A.3.1

VARRAY, 5.1.4, A.3.1

オブジェクト型の作成, 1.3.1.1 VARRAYの作成

LOBへの参照を含む, 5.1.8

CURSOR式, 2.4.2

D

参照先がないREF, 1.3.1.6.2, 1.3.1.6.3

データ型

配列型, 5.1.4

ネストした表, 5.1.5

オブジェクト型, 2.1.8

一時と汎用, 8.5

データベース管理者 (DBA)

DBAロール, 7.1.1

データベース・リンク

オブジェクト型, 2.1.8

DBAロール

ユーザー定義型, 7.1.1

宣言

PL/SQLブロックのオブジェクト, 3.1.2

PL/SQLでのオブジェクトの宣言, 3.1 DEFAULT句, 5.1.3 デフォルト値

コレクション, 5.1.3

オブジェクト型, 5.1.3

DELETE権限

オブジェクト表, 7.1.5, 7.1.5

DEREFファンクション, 2.4.3, 3.2.4 参照解除, 1.3.1.6.3, A.3.2.2

暗黙的, 1.3.1.6.3, A.3.2.2

ドット表記法, 2.1.7

PL/SQLのオブジェクト属性, 3.2.1

PL/SQLのオブジェクト・メソッド, 3.2.2

メソッドで使用, 2.2.1

DROP ANY TYPE権限, 7.1.1

「権限」も参照

DROP TYPE文

FORCEオプション, 7.2.6

ダンプ・ファイル

エクスポートおよびインポート, 4.10.1

動的メソッド・ディスパッチ, 2.3.6, 3.3 動的SQL, 3.4

E

エディション

ビュー

等価および非等価条件

ネストした表, 5.3.4

同一レベル・パーティション化

ネストした表, 5.4

進化

オブジェクト型, 1.3.1.10

継承, 9.12.1

Excel, 4.7 EXECUTE ANY TYPE権限, 7.1.1, 7.1.3

「権限」も参照

EXECUTE権限

オブジェクト型, 7.1.3

「権限」も参照

実行時のSQL文の実行, 3.4 オブジェクト型のエクスポート, 4.10.1 エクスポート・ユーティリティ

オブジェクト型, 4.10.1

EXTERNAL NAME句, 4.8.5

F

機能

新, Preface

ファイル

エクスポート/インポート・ダンプ・ファイル, 4.10.1

FINALキーワード, 2.3.2

ファイナリティの変更, 8.3.6, 9.10.3

FORCEキーワード, 6.12.2 外部キー

多対1 E-Rの表現, A.2.2.2

ファンクション索引

タイプ・メソッド, 9.5.4

G

一般的な式, 2.3.3.3

メソッドの一般的な起動, 2.3.3.3

ガイドライン

比較メソッド, 2.2.1.2.3

I

暗黙的な参照解除, 1.3.1.6.3, A.3.2.2

オブジェクト型のインポート, 4.10.1

インポート・ユーティリティ

オブジェクト型, 4.10.1

オブジェクト表のインポート, 4.10.1 IN条件, 5.3.4.2 不完全オブジェクト型, 7.2.1 不完全な型, A.3.1 索引

ネストした表, 5.1.5.1

オブジェクト型, 2.1.4

REF, 2.1.4

型判別式の列, 8.2.1

索引構成表, 5.2.1

ネストした表を格納, 5.2.1, 9.4.4.1

継承, 1.3.1.9

オーバーロード, 3.3

多重

「型の継承」を参照

単一

型進化, 9.12.1

メソッドの継承, 2.3.5 PL/SQLでのオブジェクトの初期化, 3.1 内部取得, 2.1.7.1 INSERT権限

オブジェクト表, 7.1.5, 7.1.5

インスタンス

オブジェクト型, 1.3.1.1

オブジェクト, 1.3.1.2

INSTANTIABLEキーワード

CREATE TYPE, 2.3.4

インスタンス化可能性の変更, 8.3.6

INSTEAD OFトリガー

ネストした表, 6.10.1

実行者権限

オブジェクト型, 9.6

コンストラクタの起動, 2.2.3 IOT

索引ベース表を参照, 5.2.1

IS A SET条件, 5.3.4.6 IS EMPTY条件, 5.3.4.5 IS NOT A SET条件, 5.3.4.6 IS OF typeの述語, 2.4.4

J

Java

オブジェクトの記憶域, 4.8.5

Oracle JDBCおよびOracleオブジェクト, 4.8.1

Oracle SQLJおよびOracleオブジェクト, 4.8.2

Oracleオブジェクト, 4.8

JDBC

「Oracle JDBC」を参照

K

キー

外部キー, A.2.2.2

L

リーフ・レベル属性, 2.1.4, 8.1.1

スカラー, 8.1.1

左相関, 5.3.1.2 メソッドのリテラル起動, 2.2.3.3 ロケータ

ネストした表を戻す, 8.7, 9.4.4.3, 9.4.4.3.1, A.3.6.2

ヒントの使用, 9.4.4.3.2

ロック

オブジェクト・レベル・ロック, 4.4

M

管理

オブジェクト型, 7

マップ・メソッド, 9.2, A.3.1, A.3.6.4

コレクションの比較, 5.3.4.1

オブジェクトの比較, 2.2.1.2.1

マテリアライズド・ビュー, 1.3.1.8, 9.8.2 MEMBER条件, 5.3.4.4 メンバー・メソッド, 1.3.1.3, 2.2.1 メンバー・プロシージャ

SELF IN OUT NOCOPY, 9.5.3

メソッド, 2.2.3, A.3.2

言語の選択, 9.5.1

比較, A.3.1, A.3.6.4

比較メソッド, 2.2.1.2

型階層内, 2.2.1.2.4

コンストラクタ, 1.3.1.3 コンストラクタ, 1.3.1.3, 2.2.3, 8.1.2 ドット表記法, 2.2.1 削除, 8.3.6 動的メソッド・ディスパッチ, 2.3.6 権限の実行, 7.1.2 FINAL, 2.3.2 ファンクション索引, 9.5.4 比較のガイドライン, 2.2.1.2.3 継承, 2.3.5 インスタンス化可能性, 2.3.4 起動, 2.2.1 マップ, 2.2.1.2.1, 9.2, A.3.1, A.3.6.4 オブジェクトの比較のためのマップ, 2.2.1.2.1 マップを必要とするコレクション, 5.3.4.1 メンバー, 1.3.1.3, 2.2.1 オブジェクト型, 1.3.1.3, 2.2 オーダー, 2.2.1.2.2, 9.2, A.3.1, A.3.2.3 オーバーロード, 2.3.3, 2.3.5, 2.3.5.1 オーバーライド, 2.3.2, 2.3.3, 2.3.5, 2.3.5.2 PL/SQL, 4.3 再定義, 2.3.5.2 オーバーライドの制限事項, 2.3.5.3 SELFパラメータ, 2.2.1.1 静的, 1.3.1.3, 2.2.2, 9.5.2 マルチレベル・コレクション

「コレクション」, 「マルチレベル」を参照

VARRAY記憶域, 5.2.2

多重継承 複数のサブタイプ, 2.3.3.4 MULTISET EXCEPT演算子, 5.3.5.3 MULTISET INTERSECT演算子, 5.3.5.4 多重集合の操作

ネストした表, 5.3.5

MULTISET UNION演算子, 5.3.5.5

N

名前解決

オブジェクト型, 2.1.7

ナローイング, 2.3.15.2, 2.4.8 ネストしたカーソル, A.3.6.4 ネストした表, 9.4.4

オブジェクトに追加, 8.3.5

比較, 5.3.4

COMPRESS句, 9.4.4.1

作成, 5.1.2

索引の作成, 9.4.4.2

等価および非等価条件, 5.3.4

索引構成表, 5.2.1, 9.4.4.1

索引, 5.1.5.1

INSTEAD OFトリガー, 6.10.1

ロケータ, 8.7, 9.4.4.3

多重集合の操作, 5.3.5

ピース単位操作, 5.3.2.2

問合せ, 5.3.1, A.3.1

結果のネスト解除, 5.3.1.2

ロケータとして戻す, 9.4.4.3, 9.4.4.3.1, A.3.6.2 記憶域名の指定, 8.3.5 表領域内の記憶域の指定, 5.1.5.2 記憶域, 5.2.1, 9.4.4.1, A.3.6.2 一意性, A.3.6.2 ビューにおける更新, 6.10.1 VARRAY, A.3.1, A.3.1 NESTED_TABLE_GET_REFSヒント, 9.4.4.3.2 NESTED_TABLE_ID, 5.2.1 NESTED_TABLE_IDキーワード, 5.2.1, 9.4.4.2, A.3.6.2 .NETのオブジェクトの拡張, 1.3.2 .NETストアド・プロシージャ, 1.3.2 NEWキーワード, 2.2.3 NLS_LENGTH_SEMANTICS初期化パラメータ, 2.1.2 NOCOPYコンパイラ・ヒント

メソッド, 2.2.1.1

パフォーマンスの問題, 9.5.3

メンバー・プロシージャ, 9.5.3

SELFでの使用, 2.2.1.1, 9.5.3

NOT FINALキーワード, 2.3.2 NOT MEMBER条件, 5.3.4.4 NULL

アトミック, 2.1.1

オブジェクト型, 2.1.1

O

オブジェクト・キャッシュ

オブジェクト・ビュー, 6.3

OCI, 4.4

権限, 7.1.5

Pro*C, 4.5

オブジェクトのコンストラクタ

PL/SQLでのコール, 3.2.2

PL/SQLでのパラメータの受渡し, 3.2.2

オブジェクト識別子, 1.3.1.5, 6.2 オブジェクト識別子, A.3.5

列および索引, 9.1.1.2

オブジェクト型, 8.1.2

主キー・ベース, 9.1.2.2

REF, 9.1.2

記憶域, 9.1.2

システム生成, 9.1.2.1

オブジェクト・インスタンス, 1.3.1.1, 1.3.1.2 オブジェクト・メソッド

PL/SQLでのコール, 3.2.2

オブジェクト表, 1.3.1.4, 9.1.1.2, A.3.3

制約, 2.1.3

値の削除, A.3.6.5

インポート, 4.10.1

索引, 2.1.4

値の挿入, A.3.6.3

問合せ, A.3.6.4

レプリケート, 9.8

行オブジェクト, 1.3.1.4

トリガー, 2.1.5

仮想オブジェクト表, 6.1

オブジェクト型, 1.1

ネストした表属性の追加, 8.3.5

利点, 1.2

型の変更, 8.3.5

全体での代入, 2.3.15

属性, 1.3.1.1

文字長セマンティクス, 2.1.2

コレクション・オブジェクト, 6.6

コレクション, 5.1

ネストした表, 5.1.5

可変配列(VARRAY), 5.1.4

列オブジェクト, 1.3.1.4 列オブジェクトおよび行オブジェクト, 9.1.1 比較メソッド, 2.2.1.2, A.3.1, A.3.6.4 コンストラクタ・メソッド, 1.3.1.3, 8.1.2 コンストラクタ・メソッド, 2.2.3 作成, 1.3.1.1 サブタイプの作成, 2.3.3.2 データベースの主要な機能, 1.3.1 PL/SQLブロックでの宣言, 3.1.2 依存性, 7.2 依存, 7.2.1, 8.3 進化, 1.3.1.10 進化, 8.3, 9.12.1

設計上の考慮点, 9.10

SQLJ型, 4.8.5.4

権限の例, 7.1.4 エクスポートおよびインポート, 4.10.1 FINAL, 9.10.3 FINALまたはNOT FINAL, 2.3.2 列, 6.4 不完全, 7.2, 7.2.1, 7.2.2 列オブジェクトの索引, 2.1.4 索引, 8.2.1 継承, 1.3.1.9, 2.3 PL/SQLでの初期化, 3.1.3 インスタンス, 1.3.1.1 インスタンス化可能, 2.3.4 実行者権限, 9.6 主要な機能, 1.3 キャッシュでのロック, 4.4 管理, 7 メソッド, 2.2, 2.2.1, A.3.2 PL/SQLによるメソッド, 4.3 相互依存, 7.2.1 名前解決, 2.1.7 ネストした表, 5.1.5 NOT FINAL, 9.10.3 インスタンス化不可, 2.3.4 NULL, 2.1.1 オブジェクト参照, 6.8 Oracle Type Translator, 4.5.4 パフォーマンス・チューニング, 7.4 権限, 7.1, 7.1.1 再コンパイル, 7.2.3 リモート・アクセス, 2.1.8, 6.11 行オブジェクトおよびオブジェクト識別子, 6.6 スキーマ権限, 7.1.2 「型の継承」も参照 特化 SQLJ型, 4.8.5 記憶域, 8.1 代入, 2.3.7 サブタイプ, 2.3.1 シノニム, 7.3 表別名, 2.1.7.1 トリガー, 2.1.5 表別名の使用, 2.1.7.1 ユーティリティ, 4.10 可変配列(VARRAY), 5.1.4 ビュー, 1.3.1.8 オブジェクト・ビュー, 1.3.1.8, 6

利点, 6.1

循環参照, 6.12.1

REFの定義

オブジェクト・ビューの行用, 6.2

階層, 6.13, 9.12.3

権限, 6.13.3

問合せ, 6.13.2

リレーションシップのモデル化, 6.9, 6.12 マルチレベル・コレクション, 6.6.2 ネストした表, 6.10.1 NULLオブジェクト, 6.5 OID, 6.7 REF, 6.8 レプリケート, 9.8 INSTEAD OFトリガーによる更新, 6.10 OBJECT_ID擬似列, 2.3.8.1 OBJECT_VALUE擬似列, 2.3.8.1 オブジェクト・リレーショナル・モデル, A

利点, 1.2

オブジェクトの比較, 9.2

制約, 9.9

データベースの主要な機能, 1.3.1

設計上の考慮点, 9

埋込みオブジェクト, A.3.6

主要な機能, 1.3

メソッド, 1.3.1.3, 2.2

プログラム環境, 4, 4.8

レプリケーション, 9.8

OCCI, 4.6 OCI

連想アクセス, 4.4.1

Oracleオブジェクト

プログラムの作成, 4.4.4

ナビゲーショナル・アクセス, 4.4.2 オブジェクト・キャッシュ, 4.4.3 OCIObjectFlush, 6.3 OCIObjectPin, 6.3 ODP.NET, Oracle Developer Tools for Visual Studio, 1.3.2 ODT, Microsoft共通言語, 1.3.2 OID, 9.1.2

「オブジェクト識別子」を参照

Oracle C++ Callインターフェース, 4.6 Oracle Data Provider for .NET, , 1.3.2 Oracle JDBC

Oracleオブジェクト・データのアクセス, 4.8.1

Oracleオブジェクト

「オブジェクト・リレーショナル・モデル」を参照

Oracle Objects for OLE

OraCollectionインタフェース, 4.7.3

OraObjectインタフェース, 4.7.1

OraRefインタフェース, 4.7.2

オブジェクト・リレーショナル機能のサポート, 4.7

Oracle SQLJ

カスタムJavaクラスの作成, 4.8.4.1

Oracleオブジェクトのデータ・マッピング, 4.8.3

JPublisher, 4.8.4.1

Oracleオブジェクトのサポート, 4.8.2

Oracle Type Translator (OTT), 4.5.4 OraCollectionインタフェース, 4.7.3 ORADataインタフェース, 4.8.5.1 OraObjectインタフェース, 4.7.1 OraRefインタフェース, 4.7.2 オーダー・メソッド, 2.2.1.2.2, 9.2, A.3.1, A.3.2.3 ORGANIZATION INDEX句, 5.2.1 OTT, 4.5.4 外部結合構文, 5.3.1.2, 5.3.1.4 オーバーロード, 2.3.5

継承, 3.3

メソッド, 2.3.3, 2.3.5.1

ユーザー定義コンストラクタ, 8.4.4

オーバーライド

メソッド, 2.3.3

ユーザー定義コンストラクタ, 8.4.4

メソッドのオーバーライド, 2.3.5

P

パラレル問合せ

オブジェクト, 9.11

Oracleオブジェクト使用上の制限事項, 9.11

オブジェクト・ビュー, 9.11

パーティション化, 5.4

Oracleオブジェクトを持つ表, 5.4

マルチレベルのネストした表を対象にしたピース単位操作, 5.3.2.2 pkREF, 8.1.5 PL/SQL

バインド変数

オブジェクト型, 4.3

オブジェクト・ビュー, 6.3 オブジェクトに使用, 1.3.1.3 ポリモフィズム, 1.3.1.8, 9.12.2, 9.12.3

「代入性」も参照

POWERMULTISETファンクション, 5.3.5.6 POWERMULTISET_BY_CARDINALITYファンクション, 5.3.5.7 プラグマRESTRICT_REFERENCES, A.3.1 主キー・ベースREF, 8.1.5 権限

オブジェクト型についてロールによって取得, 7.1.1

オブジェクト型に対するALTER ANY TYPE, 7.1.1

オブジェクト型の確保時にチェック, 7.1.5

オブジェクト表の列レベル, 7.1.5

オブジェクト型に対するDELETE, 7.1.5

オブジェクト型に対するDROP ANY TYPE, 7.1.1

オブジェクト型に対するEXECUTE ANY TYPE, 7.1.1, 7.1.3

オブジェクト型に対するADMIN OPTIONを含むEXECUTE ANY TYPE, 7.1.3

オブジェクト型に対するEXECUTE, 7.1.3

オブジェクト型に対するINSERT, 7.1.5

型または表内のオブジェクト型, 7.1.3

オブジェクト型とCREATE TYPE, 7.1.1

オブジェクト型とDELETE, 7.1.5

オブジェクト型とINSERT, 7.1.5

オブジェクト型とUPDATE, 7.1.5

オブジェクト型, 7.1, 7.1.1

オブジェクト型に対するSELECT, 7.1.5

オブジェクト型に対するシステム, 7.1.1

オブジェクト型に対するUNDER ANY TYPE, 7.1.1

オブジェクト型に対するUNDER ANY VIEW, 7.1.1

オブジェクト型に対するUPDATE, 7.1.5, 7.1.5

Pro*C

ユーザー定義データ型を持つ埋込みSQL, 4.5

オブジェクト・キャッシュ, 4.5

Pro*C/C++

連想アクセス, 4.5.1

Oracle型とCの型の変換, 4.5.3

ナビゲーショナル・アクセス, 4.5.2

ユーザー定義データ型, 4.4

プログラム環境

Oracleオブジェクト, 4, 4.8

Q

問合せ

セット・メンバーシップ, 9.4.4.4

ネスト解除, 9.4.1

VARRAY, 9.4.3

R

再コンパイル

オブジェクト型, 7.2.3

再定義

メソッド, 2.3.5.2

REF属性, 2.1.6 REF列, 2.1.6 REFファンクション, 2.4.5

PL/SQLのオブジェクトの操作, 3.2.4

参照, 1.3.1.6 参照, 「REF」を参照 REF, 1.3.1.6

比較, 1.3.1.6.5

制約, 2.1.6, 9.3.2

オブジェクト識別子の使用, 8.1.2, A.3.6.3

参照先がない, 1.3.1.6.2, 1.3.1.6.3, 2.1.6

参照解除, 3.2.4

参照解除, 1.3.1.6.3, A.3.2.2

暗黙的な参照解除, 1.3.1.6.3, A.3.2.2

索引, 2.1.4

索引, 9.3.3.1

オブジェクト識別子

取得, 1.3.1.6.4

確保, 6.3, 7.1.5

有効範囲付き, 1.3.1.6.1, 2.1.6, 8.1.5, 9.3.3

サイズ, 8.1.5

記憶域, 9.3.1

代入性, 2.3.8.3

代入性

表別名の使用, 2.1.7.1

WITH ROWIDオプション, 9.3.4

リモート・データベース

オブジェクト型とともに使用, 2.1.8

RESOURCEロール

ユーザー定義型, 7.1.1

結果セット全体を戻す

BULK COLLECT, 5.3.3

ロール

DBAロール, 7.1.1

RESOURCEロール, 7.1.1

行オブジェクト

記憶域, 9.1.1.2

このガイドでの例の実行, 1.3.1.1

S

サンプル・スキーマ, hrサンプル・スキーマ, hrスキーマ, サンプル・スキーマ

hr, このガイドでの例, 1.3.1.1

サンプル・スキーマ, hrスキーマ,はじめに スキーマ

オブジェクト・データ型, 4.3

オブジェクト型

列名を修飾, 2.1.7.1

SCOPE FOR制約, A.3.6.2 有効範囲付きREF, 1.3.1.6.1, 8.1.5 「参照解除」, 2.4.3, 3.2.4も参照 SELECT権限

オブジェクト表, 7.1.5

SELFパラメータ

メソッド, 2.2.1.1

SETファンクション, 5.3.5.8 単一継承 SQL

オブジェクト型のサポート, 4.1

ユーザー定義データ型, 4.1

OCI, 4.4

SQLDataインタフェース, 4.8.5.1 SQLJ

「Oracle SQL」を参照

SQLJオブジェクト型, 4.8, 9.12.4.1

作成, 4.8.5.2

Javaクラスのマッピング, 4.8.5.3

「オブジェクト型」, 「Oracle SQLJ」も参照

静的ディスパッチ, 2.3.3.3 静的メソッド, 1.3.1.3, 2.2.2 記憶域, 9.1.2

列オブジェクト, 9.1.1.1

ネストした表, 8.1.6

オブジェクト表, 8.1

REF, 8.1.5

STORE AS句, A.3.6.2 ネストした表を格納, 5.1.5.1 SUBMULTISET条件, 5.3.4.3 サブプログラム

オーバーロードおよび継承, 3.3

実行者権限を持つロール, 9.7

代入性, 2.3.7

属性

コレクション

列および行, 2.3.8, 8.2.1

制約, 2.3.12

依存性, 7.2.5

変更, 2.3.13

ナローイング, 2.3.15.2

OBJECT_ID, 2.3.8.1

OBJECT_VALUE, 2.3.8.1

変更の制限事項, 2.3.14

無効化, 2.3.11

ビュー, 2.3.8

ビュー, 9.12.3

ワイドニング, 2.3.15.1

オブジェクト型の代入性

オーバーロード, 3.3

代入可能な列

サブタイプの削除, 2.3.10

サブタイプ

作成, 2.3.3

代入可能な列内での削除, 2.3.10

階層

属性の索引付け, 8.2.2

複数の, 2.3.3.4

オブジェクト型, 2.3.1

特化, 9.12.1

スーパータイプ属性, 2.3.8.2

スーパータイプ

サブタイプの属性, 2.3.8.2

階層内のベース

シノニム

オブジェクト型, 7.3

SYS_TYPEIDファンクション, 2.4.6, 8.2.1 SYS.ANYDATA, 8.5 SYS.ANYDATASET, 8.5 SYS.ANYTYPE, 8.5 システム権限

Admin Option, 7.1.3

オブジェクト型, 7.1.1

「権限」も参照

T

TABLE

ファンクション, 2.4.7

表依存性, 7.2.4 TABLE式, 5.1.5, 5.3.1.3 TABLE式の副問合せ

制限事項, 5.3.1.2

TABLE式, 5.3.1.2, 9.4.1 表

別名, 2.1.7.1

オブジェクト表の制約, 2.1.3

ファンクション, 2.4.7

ネストした表の索引, 2.1.4

ネストした表, 5.1.5

オブジェクト

「オブジェクト表」を参照

オブジェクト表, 1.3.1.4

仮想, 6.1

列名を修飾, 2.1.7, 2.1.7.1 TREATファンクション, 2.3.8, 2.3.15.2, 2.4.4, 2.4.8, 8.2.2 トリガー

INSTEAD OFトリガー

オブジェクト・ビュー

オブジェクト型, 2.1.5 型依存性, 7.2.5 型依存性, 7.2.4 型進化, 1.3.1.10

「オブジェクト型」を参照

型階層

メソッド, 2.2.1.2.4

型の継承

ファイナリティ, 2.3.2

インスタンス化可能性, 2.3.4

メソッド, 2.3.5

オブジェクト型

「継承」を参照

サブタイプの特化, 2.3.1

型ID, 2.4.6, 8.2.1 型

「データ型」, 「オブジェクト型」を参照

U

UNDER ANY TYPE権限, 7.1.1

「権限」も参照

UNDER ANY VIEW権限, 7.1.1

「権限」も参照

UNDERキーワード

CREATE TYPE, 2.3.3

未初期化オブジェクト

PL/SQLのオブジェクト, 3.1.3

問合せのネスト解除, 9.4.1 コレクションへの問合せのネスト解除, 5.3.1.3 マルチレベル・コレクションを伴う問合せのネスト解除, 5.3.1.4 UPDATE権限

オブジェクト表, 7.1.5, 7.1.5, 7.1.5

更新

オブジェクト・ビュー, 6.10

UPGRADE..STORE AS, 8.3.5 ユーザー定義集計ファンクション, 8.6 ユーザー定義コンストラクタ, 8.4.3, 8.4.4 ユーザー定義データ型, 1.1

「オブジェクト型」を参照

ユーザー定義型

リモート・データベース, 2.1.8

オブジェクト・リレーショナル・モデル, A

USING句, 4.8.5 オブジェクトをサポートするユーティリティ, 4.10

V

妥当性チェック

失敗, 8.3.7

オブジェクト型, 8.3.6

VALUEファンクション, 2.4.9, 3.2.2 変数

バインド変数

オブジェクト型, 4.3

オブジェクト変数, 6.3 VARRAY, 5.1.4

アクセス, 9.4.3

作成, 5.1.2

VARRAYの作成, 5.1.8

要素の数の増加, 5.1.7

問合せ, 9.4.3

「配列」, 「コレクション」も参照

記憶域, 5.2.2, 9.4.2

更新, 9.4.3

ネストした表, A.3.1, A.3.1

ビュー

オブジェクト, 1.3.1.8

「オブジェクト・ビュー」も参照

代入性, 2.3.8

更新可能性, 6.10

Visual Basic, 4.7

W

ワイドニング

代入性, 2.3.15.1

X

XML, 4.9

XMLType, 5.1.4

XMLTypeビュー, 4.9

Oracleの法律上の注意点

コピーライト

Copyright © 1994-2018, Oracle and/or its affiliates. All rights reserved.

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクルまでご連絡ください。

制限付権利について

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、Oracle Corporationおよびその関連会社は一切の責任を負いかねます。

商標と登録商標について

OracleおよびJavaはオラクルおよびその関連会社の登録商標です。その他の社名、商品名等は各社の商標または登録商標である場合があります。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

Pre-General Availability (一般提供前)版のドキュメントについて

このドキュメントがPre-General Availability (一般提供前)版の場合:

このドキュメントはPre-General Availability (一般提供前)版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。Oracle Corporationおよびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

非公開のPre-General Availability (一般提供前)版のドキュメントについて

このドキュメントが非公開のPre-General Availability (一般提供前)版の場合:

このドキュメントに含まれる情報は、情報の共有のみを目的としたものであって、顧客諮問委員会(Customer Advisory Board)のメンバーとしてのお客様の立場でのみ、またはお客様のPre-General Availability Trial Agreement (Pre-GAトライアル契約)のみに従って検討されるべきものとします。マテリアル、コード、または機能の提供をお約束するものではなく、購入決定を行う際の判断材料とすべきではありません。このドキュメントに記載されている特徴または機能の開発、リリースおよび時期については、オラクルの裁量により決定されます。

このドキュメントには、ソフトウェアまたは印刷物などの形式を問わず、オラクルが独占的な権利を有する財産的情報が含まれています。この機密資料へのアクセスと使用は、お客様とオラクルとの間で締結され、お客様が遵守に同意した、Oracle Master Agreement、Oracle License and Oracle Services Agreement (オラクル・ライセンスおよびサービスに関する契約書)、Oracle Partner Network Agreement、Oracle Distribution Agreementまたはその他のライセンス契約の条件に従うものとします。このドキュメントとその内容の開示、コピー、複製および配布には、オラクルによる事前の承諾を必要とします。このドキュメントはライセンス契約の一部となるものではなく、オラクルおよびその子会社や関連会社との契約を構成するものではありません。

ドキュメントのアクセシビリティ

オラクルのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご契約のお客様には、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info)か、聴覚に障害のあるお客様は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。