オブジェクト指向、Javaを取り入れた
新しい業界標準「SQL99」詳細解説

第二章 柔軟さを増したデータ構造(3)


オブジェクトリレーショナル

■ユーザー定義構造型と列オブジェクト

  SQL99がオブジェクト・リレーショナル技術によって実現しようとしているカプセル化、オブジェクト識別性、継承などは、これから説明するユーザー定義構造型が基本である。

 すでに触れたように複数の任意の定義済みの型を組み合わせて、新たに1つの型を生成することができる。その型のことを構造型と呼ぶ。従来、リレーショナルデータベースの表の列の型はスカラな単一のデータ型に制限されていたが、その列に任意の構造を持つ複合データ型をユーザー定義構造型によって実現できることを意味している。

 構造型は、表定義のCREATE TABLE文によく似たCREATE TYPE文によって定義する。表の「列」に対応するものを、型では「属性」と呼び、その定義の例を図19に示す。

図19 ユーザー定義構造型と列オブジェクトの例

 この例では、郵便番号と都道府県名と市区郡番地の3個の属性からなる住所型を定義した。各属性は組込みデータ型を使用しているが、定義済みのユーザー定義DISTINCT型でもよいし、別の構造型でもよい。さらに住所型に、この型固有のメソッドとしてaddress_string( )を定義した。1個の型に複数のメソッドを宣言することができ、メソッドの処理内容は、別途、CREATE METHOD文の中に記述する。メソッドは、ユーザー定義関数と同様に外部ルーチンを呼び出してもよいし、メソッド内部にBEGIN句からEND句の間にSQLルーチンを記述してもよい。

 構造型の定義の中にINSTANTIABLEとあるのは、この型が固有のインスタンスを持てることを指定していて、システムによって型の名前と同名のコンストラクタ関数が自動的に提供される(備考:すこし話が難しくなるが、NOT INSTANTIABLEを指定した場合は、システム提供のコンストラクタ関数は生成されず、その型固有のインスタンスを持たない。その場合はINSTANTIABLEを指定した副型を定義してはじめて実体としてのインスタンスが存在することができる。ちょうどオブジェクト指向言語の抽象クラスに似た性質を持たせることができる)。 実体として住所を存在させる方法はすぐ後に述べる。また、NOT FINALとあるのは、この型が副型(サブタイプ)を持つことができることを指定していて、SQL99では構造型は必ずNOT FINALを指定し、DISTINCT型はFINALを指定しなければならない。

 図19にはまた、社員表を定義するCREATE TABLE文の中の現住所列の型として、いま定義した住所型を使用している例を示した。それでは、構造型の列を含む社員表に対するデータ操作はどのように行うのだろうか。その基本的なデータ操作例を図20に示す。

図20 列オブジェクトを含む表への操作例

 データ操作の手順は以下に示すようなものとなる。

  1. 社員表への行の挿入:INSERT文を使用し、構造型である住所型の現住所列の値を入れるために、新たに導入されたNEW演算子を使用する。NEW演算子は、構造型のインスタンスを初期化し、その構造型のコンストラクタを呼び出して、与えられた引数値にもとづいてインスタンスを生成する。ここでは住所型のコンストラクタである住所型( )の3個の引数がそれぞれ住所型の郵便番号、都道府県名、市区群番地の各属性値になって、社員表の現住所列に格納される(備考:物理的にどのように格納されるかは実装に任されている)。この社員表の現住所列のようにその型が構造型である場合、その列に構造型のオブジェクトが格納されているという意味で、特に「列オブジェクト」と呼ぶ(これに対して行オブジェクトと呼ばれるものがあるが後述する)。

  2. 社員表の列オブジェクトの照会と列メソッドの呼び出し:型の属性を参照するためには属性名と同じ名前のオブザーバ(observer)を呼び出す。例えば、住所型の郵便番号を参照するには、郵便番号( )と書く。オブザーバの( )は省略してもよい。そしてSELECT文の中で構造型の中の1個の属性を参照したり、構造型の中の1個のメソッドを呼び出すためには、次のような列名とオブザーバまたはメソッド名の間を“.”(ピリオド)で挟んだ ドット記法と呼ばれる形式を使う。
    <列名>.<型の属性オブザーバ>
    <列名>.<型のメソッド名>

  3. 社員表の照会と更新:構造型の属性値を更新するためには、属性名と同じ名前のミュテータ(mutator)を呼び出す。形式はオブザーバと同じである。また構造型である現住所列をWHERE句の比較値に指定したり、SET句の置換値に指定することができる。この場合も、INSERT文のときと同様にNEW演算子を使用して住所型のコンストラクタを呼び出せばよい。

 上記の簡単な例からもわかるように、ユーザーは構造型の列オブジェクトが、その内部がどのような実装になっているのかを知る必要がなく、列オブジェクトの属性を生成するにはインターフェースが明確なシステム提供のコンストラクタを、参照するにはオブザーバを、更新するにはミュテータを使用するので(あるいは使用しなければならないので)、構造型のオブジェクトはカプセル化されていると言える。

■ユーザー定義構造型と行オブジェクト

  前述の例では、住所を構造型として定義したが、社員も構造型として定義することができる。その例を図21に示す。

図21 ユーザー定義構造型と行オブジェクトの例

 ここでは新たに定義した社員型に、あとで継承の例を説明するために基本給の属性を追加し、社員の給与額を計算するメソッドsalary( )を定義した。この社員型の属性値を表のデータとしてアクセスするには、図の例に示したようなCREATE TABLE文によって型付き表(typed table)として定義する必要がある。構文の概要は次のとおりである。

CREATE TABLE <表名> OF <構造型名>
(REF IS <自己参照列名>
SYSTEM GENERATED
またはUSER GENERATED);

 表名の次のOFに続けて、どの構造型に基づいているかを指定する。特に重要な点は、型付き表に行が挿入されて構造型のインスタンスが生成されるときに、その表の行を一意に特定するオブジェクトIDが割り当てられて構造型のインスタンスに追加されることである。このオブジェクトIDは、後述する副表の行を含めて一意でなければならない。オブジェクトIDを参照する列名を「REF IS」以下で指定するが、オブジェクトIDの生成は、システムに任せるかユーザーが割り当てるかを選択することができる。

 このように型付き表では、表の行と構造型のインスタンスの構造が同じなので(正確には、型付き表にはオブジェクトIDの列が追加されている)、この場合の構造型のオブジェクトを行オブジェクトと呼ぶ。 型付き表の行オブジェクトのデータ操作の例を図22に示す。

図22 型付き表へのデータ操作の例

  1. 行の挿入:INSERT文で行うが、特徴は、構造型のインスタンスを一意に識別するためのオブジェクトIDをVALUES句の先頭に与えることである。

  2. 行の照会:列オブジェクトのところで紹介したデータ操作方法と一見すると似ているが、列オブジェクトがドット記法で属性を参照したのに対して(つまりオブザーバとミュテータを使用)、行オブジェクトでは属性名をそのままSQL文の列名として記述する点が異なる。また行オブジェクトにはオブジェクトIDが追加されているので、もし「SELECT * FROM 社員表」を発行した場合は、結果行の先頭列にオブジェクトIDのOID列が先頭に来て、それに社員型の属性が続く。なお例の中で、「田中一郎」さんの給与額が20万円でなく23万円に変わっているのは、メソッドsalary()が呼び出されて、そのメソッドの中で田中さんの基本給額の20万円とと最低保証給額の23万円を比較して大きい方の値を返却したということを想定している。

副表(サブテーブル)と継承(インヘリタンス)

 SQL99では、構造型に副型(サブタイプ)を持たせることができ、その例を図23に示す。

図23 副型と副表の例

構文の概要は次の通りである。

CREATE TYPE <副型名> UNDER <上位型名>
(属性名 型名,
..... )
NOT FINAL
OVERRIDING METHOD <メソッド名> RETURNS ....;

 この例では、CREATE TYPE文に「UNDER 社員型」を指定することによってプログラマ型が社員型の副型であることを指定し、プログラマ型に特有な属性を2個追加した。(社員型の定義のときに社員型が副型を持てるようにNOT FINALを指定したことを思い出していただきたい。)さらに社員型に宣言したのと同じ名前のメソッドsalary()をオーバライドする(上書きする)というオプションを付けて宣言した。プログラマ型のメソッドsalary()は、基本給額にプログラマ型の技能級の属性値に対応した技能給を加算する計算ロジックが含まれているものとする。

 次にプログラマ型の属性値を列データとしてアクセスするために、プログラマ表という型付き表を定義する。構文の概要は次のとおりである。

型付き表の定義構文:

CREATE TABLE <副表名> OF <構造型名>
UNDER <上位表名>
(REF IS <自己参照列名>
SYSTEM GENERATED
またはUSER GENERATED);

 プログラマ表が社員表の副表(サブテーブル)であることを示すために「UNDER 社員表」を指定する。これで社員表が上位表(スーパーテーブル)で、プログラマ表が副表(サブテーブル)であるという関係が定義できたことになる。このような上位型と副型の関係を型階層、対応する上位表と副表の関係を表階層と呼ぶ。 プログラマ型は上位の社員型のすべての属性とメソッドを継承するので、プログラマ表も同様に、社員表のすべての列とメソッドを継承する。言い替えれば、プログラマ型には必要な属性だけを、つまり差分だけを追加して定義すればよい。

  なお上位表は、複数の副表を持つことができる。ただしSQL99では副表から見て上位表は1個に制限されている(備考:副表が複数の上位表を持ついわゆる多重定義はSQL4での検討課題になっている。)。

 それでは表階層関係にある社員表とプログラマ表へのデータ操作の違いを図24で見てみよう。

図24 表階層の表への照会

  1. 照会1:上位表である社員表をFROM句に指定したSELECT文を発行した。結果は、社員表とプログラマ表の行をユニオンした行が答えとして返却される。結果行の列には社員表に定義された列だけを含めることができる。ところで、もし社員型の副型として管理職社員型を定義し、社員表の副表として管理職社員表を追加定義したとしよう。そしてもしすべての社員の情報を得るためにそれらの表をユニオンする必要がある場合、表階層の関係になければすべての表をFROM句に明示指定したSELECT文のユニオン操作(UNION)を行う必要があり、追加したところを変更しなければならない。表階層の関係にある場合は、上位表だけをFROM句に指定するだけでよく、副表の増減には影響を受けないSELECT文を書くことができる。
    さらに注目していただきたいのは、給与額列である。 もしプログラマ型にメソッドsalary( )が宣言されていなければ、上位型である社員型のメソッドsalary( )が継承されて使用される。しかしこの例では、社員表の行である「田中一郎」さんの給与額は社員型用のメソッドsalary( )が呼び出されて計算されるが、プログラマ表の行である「鈴木二郎」さんの給与額は、プログラマ型用のメソッドsalary( )が呼び出されて計算される。このように同じ名前と同じシグネチャ(同じ引数の数と同じ引数のデータ型)であれば構造型に対応した固有のメソッドが実行時に選択される。すなわち、メソッドには多態性(ポリフォミズム)があり、遅延バインディングの性質がある。もし上位型のメソッドをそのまま継承するものと、副型固有のメソッドを上手に切り出して、差分だけをメソッドとして追加すれば、また必要であれば上位型メソッドをオーバライドすることによって効果的な差分開発が可能になるだろう。

  2. 照会2:副表をFROM句に指定したSELECT文を発行した。容易に想像がつくように副表だけが照会の対象となる。

  3. 照会3:上位表である社員表だけの行を照会の対象にしたい場合は、FROM句にONLYを明示指定すればよい。

■副型を持つ列オブジェクト

  これまでに社員型とプログラマ型を定義して、それぞれ社員表とプログラマ表という型付き表を定義した。ここで少し観点を変えて、図25のようなプロジェクト表を定義する。

図25 副型を持つ列オブジェクトの例

 プロジェクト要員表には、プロジェクトに参加している要員が社員型として定義されている。このプロジェクト要員表への表の行の挿入のうち要員列の部分は、すでに説明したようにNEW演算子を使用する。図の例では、1回目のINSERT文は要員列の値として「田中一郎」さんを社員型の列オブジェクトに生成した行を挿入し、2回目のINSERT文は要員列の値として「鈴木二郎」さんをプログラマ型の列オブジェクトに生成した行を挿入している。

 このように型階層にある上位型も副型も表の同じ列に格納でき、ちょうどプロジェクト要員表の行、すなわちプロジェクト要員オブジェクトの中に、社員オブジェクトまたはプログラマオブジェクトがそのまま格納されているように見える。どのように実装されるかは別にして、論理的にはオブジェクトの中に別のオブジェクトを直接に埋め込むことができる。当然、SELECT文などで列オブジェクトの各属性を区別してドット記法を使用して参照することができ、またメソッドも列オブジェクトの型に応じて対応するものが呼び出される。

■行オブジェクトと経路式

  プロジェクト要員表の例を考えた場合、同じ社員が複数のプロジェクトに要員として参加することが十分にありえる。その場合、要員列にそのまま社員オブジェクトなりプログラマオブジェクトを格納してしまうのは適切でない。なぜならば同じ社員オブジェクトやプログラマオブジェクトが重複して存在することになるからである。この問題を解決するには、行オブジェクトを利用する。プロジェクト要員表の要員列が型付き表の社員表を参照するように変更した例を図26に示す。

図26 行オブジェクト経路式の例

 プロジェクト要員表の要員列のREF型は、社員型のオブジェクトを参照することを指定している。社員型をもとにした型付き表は社員表だけとは限らないので、WITH OPTIONS SCOPE句によって、その要員列が参照する表が社員表であることを指定する(例えば、社員が属する同好会会員表のような表も社員型の型付き表として定義されているかもしれない)。

図27 行オブジェクトへのデータ操作例

 行オブジェクトへの操作例を図27に示す。 プロジェクト要員表に行をINSERT文によって挿入するときは、要員列に社員表またはプログラマ表のプロジェクトに参加する人の行オブジェクトのオブジェクトIDを設定する。これによって、要員列には行オブジェクトを一意に識別するオブジェクトIDだけが入る。 オブジェクトIDは、ちょうどリレーショナルモデルの主キーに、参照列は外部キーに相当するが、主キーとの違いは、オブジェクトIDは表階層の間で一意性が保証されていることである。

 プロジェクト要員表から社員表の列を参照する場合は、「要員->社員名」のように参照したい列への経路を「X->Y」の記号で示す経路式(path expression)と呼ばれる記法を使用する。Xは参照列名で、Yは目的表の列名である。そして式はX列に合致するオブジェクトIDを持つ目的表の行を探し、その行のY列の値を返却するか、存在しなければナルを返却せよという意味である。もし従来のリレーショナルの表であれば、プロジェクト要員表と社員表との間の相関副照会(副問い合せ)か、またはを左外結合(LEFT OUTER JOIN)の操作で表現できるが、目的表の名前をSELECT文に明示的に指定する必要がある。一方、経路式では、目的表の表名を書く必要がない。見方によっては、参照列(上の例の要員列)に格納されたオブジェクトIDはちょうど、プロジェクト表から社員表またはプロジェクト表への直接ポインタのよううに見えるので、SQL設計者は、そのポインタをどのようにたどるべきかを考えることになるだろう(備考:「ポインタ」が物理的にどのようなものかは実装に任されている)。


オブジェクトビュー

 SQL99のオブジェクトリレーショナルでは、型付き表に対して型付きビューを定義することができる。その例を図28に示すが、少し複雑である。

 まず型付き表のもとになっている構造型の属性のうち、ビューで参照を許す属性だけを含んだ、いわばサブセットになった構造型を新たに定義する。それを図の例では、社員表の社員型に対しては社員ビュー型を、プログラマ表のプログラマ型に対してはプログラマビュー型として定義した。従来通りビューはCREATE VIEW文で定義するが、OF句によって社員ビューが社員ビュー型に付随したビューであることを指定する。AS句では、ビューの中で実行したいSELECT文を記述する。ここでは対象範囲を社員表に限定し、社員ID列と社員名列と現住所列だけを参照可能にした社員ビューを定義している。したがって、このビューを使用すれば、社員表の誕生日や基本給額、および副表の行の存在を隠すことができる。

 副表に対しても同様に型付きビューを定義できる。ここではプログラマビューを定義しているが、OF句によってプログラマビューの型がプログラマビュー型であることを定義すると同時にUNDER句によって社員ビューの副ビューであることも指定する。


図28 オブジェクトビューの定義例


とびら 新しい業界標準「SQL99」詳細解説

第一章 高度なデータ操作

SQL99の背景と特徴
SQL99の主な機能強化
  スキーマ定義の新機能
  データ操作と演算子の新機能
  整合性の新機能
  セキュリティ(機密保護)の新機能
  トランザクション管理の新機能
  クライアント/サーバの新機能
高度なリレーショナル操作
  共通表式 WITH句
  再帰SQL
OLAPによる分析手順
  ROLLUP
  CUBE
  GROUPING SETS
ユニオン(UNION)経由の更新
  結合(JOIN)経由の更新


第二章 柔軟さを増したデータ構造

ユーザー定義可能な新しいデータ
  新しい組込みデータ型
  真理値型(BOOLEAN型)
  配列型(ARRAY型)
LOBとは
  LOBデータ型の定義
  LOBデータ型の取り扱い
  LOBロケータの使用
  HOLD LOCATORとFREE LOCATOR
  LOBの挿入(更新)と検索方法の拡張
ユーザー定義型
  ユーザー定義DISTINCT型
ユーザー定義関数
関数のオーバーロード

オブジェクト・リレーショナル
  ユーザー定義構造型と列オブジェクト
  ユーザー定義構造型と行オブジェクト
副表(サブテーブル)と継承(インヘリタンス)
  副型を持つ列オブジェクト
  行オブジェクトと経路式
オブジェクトビュー
トリガ


第三章 SQLJと今後の標準化動向

クライアント/サーバ環境のための機能強化
  ストアドプロシージャ
  新しいプロシージャ言語
静的埋め込みSQLを実現する「SQLJ」
  パフォーマンスの向上と移植性
  SQLJのコンパイル
  SQLJの記述方法
  SQLJ 対 JDBC
  イテレータの使用
  SQLデータ型としてのJavaクラス
オブジェクトリレーショナル機能の応用例
  SQL/MM全文検索(フルテキスト)
  SQL/MM地理情報(スペーシャル)
今後のSQL標準化動向
  コレクション型の拡張
  オブジェクトリレーショナル機能の拡張
  SQL/MED
  OLAP機能の拡張
  自由度が高まるデータアクセス



「Master of IP Network総合インデックス」



Master of IP Network フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Master of IP Network 記事ランキング

本日 月間