構造型は、属性 で構成される明確な構造を持つオブジェクトをモデル化するのに役立ちます。属性は、タイプのインスタンスを記述するプロパティーです。たとえば、幾何学形状は、デカルト座標のリストを属性として持っています。人物には、名前、住所などの属性があります。部門には、名前、または他の種類の ID があります。
タイプを作成するには、タイプの名前、属性名、およびデータ・タイプを指定する必要があります。また、このタイプの参照タイプをシステム内で表現する方法を指定することもできます。 BusinessUnit_t タイプを作成する SQL は、次のとおりです。
CREATE TYPE BusinessUnit_t AS (Name VARCHAR(20), Headcount INT) REF USING INT MODE DB2SQL;
AS 文節では、タイプに関連した属性定義を指定します。 BusinessUnit_t は、 Name と Headcount という 2 つの属性を持つタイプです。構造型を作成するには、 CREATE TYPE ステートメントに MODE DB2SQL 文節を入れます。 REF USING 文節の詳細については、 参照タイプとその表示タイプを参照してください。
構造型は、従来のリレーショナル・データ・タイプの機能を拡張しています。拡張された主な 2 つの機能は、継承というプロパティーと、構造型のインスタンスを表の中に行としてまたは列の中に値として保管する機能です。次のセクションで、これらの機能を概説します。
図 7. 構造型 Employee_t は Person_t を継承している
![]() |
CREATE TABLE Person OF Person_t ...
表の中のそれぞれの列の名前とデータ・タイプは、指示されている構造型の属性のいずれか 1 つから派生したものです。このような表を、タイプ付き表といいます。
CREATE TABLE Properties (ParcelNum INT, Photo BLOB(2K), Address Address_t) ...
別の構造型の下に 構造型を作成することができます。この場合、新しく作成された構造型は、元の構造型のサブタイプ になります。元の構造型は、スーパータイプ です。サブタイプは、スーパータイプのすべての属性を継承し、さらに独自の追加の属性を持つこともできます。
たとえば、データ・モデルが、管理者という特殊な従業員を表す必要があるとします。管理者には、管理者ではない従業員よりも多くの属性があります。 Manager_t タイプは、従業員のために定義されている属性を継承していますが、管理者だけに適用される特別賞与属性など、いくつかの独自の追加の属性によっても定義されています。本書の例に使用されているタイプ階層を図 8 に示します。 Address_t のタイプ階層は、構造型インスタンスの列への挿入で定義されています。
図 8. タイプ階層 (BusinessUnit_t と Person_t)
![]() |
図 8 では、人物タイプ Person_t は、この階層のルート・タイプ です。 Person_t は、下位のタイプ (ここでは、 Employee_t という名前のタイプと Student_t という名前のタイプ) のスーパータイプでもあります。サブタイプとスーパータイプとの間には推移的な関係があります。つまり、サブタイプとスーパータイプとの間の関係は、タイプ階層全体で保持されるということです。したがって、Person_t は、 Manager_t と Architect_t のスーパータイプでもあるのです。
構造型の概説で定義されているタイプ BusinessUnit_t は、サブタイプを持っていません。 構造型インスタンスの列への挿入で定義されている Address_t は、 Germany_addr_t、Brazil_addr_t、および US_addr_t というサブタイプを持っています。
Person_t の CREATE TYPE ステートメントは、 Person_t が INSTANTIABLE であると宣言しています。 INSTANTIABLE または NOT INSTANTIABLE 文節を使用した構造型の宣言については、 構造型の付加的な特性を参照してください。
次の SQL ステートメントは、Person_t タイプ階層を作成します。
CREATE TYPE Person_t AS (Name VARCHAR(20), Age INT, Address Address_t) INSTANTIABLE REF USING VARCHAR(13) FOR BIT DATA MODE DB2SQL; CREATE TYPE Employee_t UNDER Person_t AS (SerialNum INT, Salary DECIMAL (9,2), Dept REF(BusinessUnit_t)) MODE DB2SQL; CREATE TYPE Student_t UNDER Person_t AS (SerialNum CHAR(6), GPA DOUBLE) MODE DB2SQL; CREATE TYPE Manager_t UNDER Employee_t AS (Bonus DECIMAL (7,2)) MODE DB2SQL; CREATE TYPE Architect_t UNDER Employee_t AS (StockOption INTEGER) MODE DB2SQL;
Person_t は、Name、 Age および Address という 3 つの属性を持っています。 2 つのサブタイプ Employee_t と Student_t は、両方とも Person_t の属性を継承していて、それぞれのタイプに固有のいくつかの追加の属性も持っています。たとえば、従業員と生徒には両方とも通し番号が振られていますが、生徒の通し番号に使用される形式は、従業員の通し番号に使用される形式とは異なります。
注: | Person_t タイプから作成されるタイプ付き表には、構造型 Address_t の列 Address が入っています。すべての構造型の列の場合と同様に、この列の構造型のための transform 関数を定義する必要があります。 transform 関数の定義方法の詳細については、 ホスト言語プログラムへのマッピングの作成: transform 関数を参照してください。 |
最後に、Manager_t と Architect_t は両方とも、 Employee_t のサブタイプです。つまり、これらは Employee_t のすべての属性を継承していて、その属性をそれぞれのタイプに適合するよう拡張しているのです。したがって、タイプ Manager_t のインスタンスは、 Name、Age、Address、 SerialNum、Salary、Dept、および Bonus という合計 7 つの属性を持つことになります。
DB2 は、開発者が作成するすべての構造型について、自動的にコンパニオン・タイプを作成します。コンパニオン・タイプのことを参照タイプ といい、参照先の構造型のことを参照先タイプ といいます。タイプ付き表では、タイプ付き表での構造型の使用で説明されているように、参照タイプを特別な方法で使用できます。 SQL ステートメントでは、他のユーザー定義のタイプと同様に、参照タイプを使用することもできます。 SQL ステートメントで参照タイプを使用するには、 REF(type-name) を使用します。 type-name は参照先タイプのことです。
DB2 は、参照タイプをタイプ付き表の中のオブジェクト識別子列のタイプとして使用します。オブジェクト識別子によって、タイプ付き表階層の中の行オブジェクトが一意的に識別されます。 DB2 は、参照タイプを使用して、行の参照をタイプ付き表に保管することもします。参照タイプを使用して、表の中のそれぞれの行を参照することができます。参照の使用法の詳細については、参照タイプの使用を参照してください。タイプ付き表の詳細については、オブジェクトのタイプ付き表への保管を参照してください。
参照は大文字で入力します。したがって、式の中でタイプを使用する方法がなければなりません。タイプ階層のルート・タイプを作成する時に、 CREATE TYPE ステートメントの REF USING 文節を使用して、参照のための基本タイプを指定することができます。参照のための基本タイプのことを表示タイプ といいます。 REF USING 文節を使用して表示タイプを指定しない場合は、 DB2 は VARCHAR(16) FOR BIT DATA というデフォルト・データ・タイプを使用します。ルート・タイプの表示タイプは、そのすべてのサブタイプに継承されます。 REF USING 文節を使用できるのは、階層のルート・タイプを定義するときだけです。このセクションで一貫して使用されている例では、 BusinessUnit_t タイプの表示タイプは INTEGER であり、 Person_t の表示タイプは VARCHAR(13) です。
DB2 は、参照タイプと表示タイプとの間で値を双方向にキャストする関数を自動的に作成します。 CREATE TYPE ステートメントには、 SQL 解説書 で説明されている CAST WITH 文節をオプションで指定することができます。この文節を指定すると、これら 2 つの cast 関数の名前を選択することができます。デフォルトでは、2 つの cast 関数の名前は、構造型の名前とその参照表示タイプの名前と同じです。たとえば、構造型階層の作成の CREATE TYPE Person_t ステートメントは、次の関数を自動的に作成します。
CREATE FUNCTION VARCHAR(REF(Person_t)) RETURNS VARCHAR
DB2 は、次のような逆の操作を行う関数も作成します。
CREATE FUNCTION Person_t(VARCHAR(13)) RETURNS REF(Person_t)
タイプ付き表に新しい値を挿入する必要がある時、あるいは参照値を別の値と比較する時には、いつでもこれらの cast 関数を使用できます。
DB2 は、=、<>、<、<=、>、および >= という比較演算子を使用して参照タイプを比較することのできる関数も作成します。参照タイプ用の比較演算子の詳細については、 SQL 解説書 を参照してください。
開発者が作成するすべての構造型について、 DB2 は、構造型の値を構成、監視、変更するのに使用できる一連の関数を暗黙的に作成します。つまり、たとえば、タイプ Person_t のために、このタイプの作成時に DB2 は次の関数とメソッドを作成するということです。
CREATE FUNCTION Person_t ( ) RETURNS Person_t
サブタイプ Manager_t については、次のステートメントが実行された場合と同じように constructor 関数が作成されます。
CREATE FUNCTION Manager_t ( ) RETURNS Manager_t
列の中に挿入するタイプのインスタンスを構成するには、 constructor 関数を mutator メソッドと一緒に使用します。タイプを列ではなく表に保管する場合は、タイプのインスタンスを挿入するのに、 constructor 関数を mutator メソッドと一緒に使用する必要はありません。データのタイプ付き表への挿入方法の詳細については、 構造型値が入っている行の挿入を参照してください。
age のために DB2 が作成する mutator メソッドは、たとえば、次のステートメントが実行された場合と同様になります。
ALTER TYPE Person_t ADD METHOD AGE(int) RETURNS Person_t;
オブジェクトの変更の詳細については、 構造型値の検索と変更を参照してください。
タイプ Person_t の 属性 age のために DB2 が作成する observerメソッドは、たとえば、DB2 が次のステートメントを発行する場合と同様になります。
ALTER TYPE Person_t ADD METHOD AGE() RETURNS INTEGER;
observer メソッドの使用法の詳細については、 構造型値の検索と変更を参照してください。
構造型に対してメソッドを呼び出すには、メソッド呼び出し演算子 '..' を使用します。メソッドの呼び出しの詳細については、 SQL 解説書 を参照してください。
構造型の振る舞いを定義するために、ユーザー定義のメソッドを作成することができます。特殊タイプのためのメソッドを作成することはできません。メソッドは 1 つのタイプのために固有に作成されるので、タイプとその振る舞いは緊密に結び合わされているという点を除けば、メソッドを作成することは、関数を作成することと似ています。
CREATE METHOD ステートメントを発行する前に、メソッド仕様をタイプと関連付けておく必要があります。次のステートメントは、 calc_bonus というメソッドのメソッド仕様を Employee_t タイプに追加します。
ALTER TYPE Employee_t ADD METHOD calc_bonus (rate DOUBLE) RETURNS DECIMAL(7,2) LANGUAGE SQL CONTAINS SQL NO EXTERNAL ACTION DETERMINISTIC;
メソッド仕様をタイプと関連付けた後は、メソッドをメソッド仕様に従って外部メソッドまたは SQL 形式のメソッドとして作成することによって、タイプの振る舞いを定義することができます。たとえば、次のステートメントは、タイプ Employee_t と同じスキーマに常駐する calc_bonus という SQL メソッドを登録します。
CREATE METHOD calc_bonus (rate DOUBLE) FOR Employee_t RETURN SELF..salary * rate;
calc_bonus という名前のメソッドは、パラメーターの数または種類が異なっている限り、あるいは異なるタイプ階層の中のタイプについて定義されている限り、いくつでも作成することができます。つまり、Architect_t については、パラメーターの種類とパラメーターの数が同じである calc_bonus という別のメソッドを作成することはできないということです。
注: | DB2 は現在、動的ディスパッチングをサポートしていません。これは、あるタイプのためにあるメソッドを宣言したなら、そのメソッドを同じ数のパラメーターを使用して、サブタイプのために再定義することはできないということです。この回避方法としては、TYPE 述部を使用して動的タイプを判別してから、 TREAT AS 文節を使用してそれぞれの動的タイプのために異なるメソッドを呼び出すという方法があります。サブタイプを処理する transform 関数の例については、 サブタイプ・データの DB2 からの検索 (バインドアウト)を参照してください。 |
メソッドの登録、書き込み、および呼び出しの詳細については、 ユーザー定義関数 (UDF) およびメソッドおよびユーザー定義関数 (UDF) とメソッドの作成を参照してください。
構造型のインスタンスは、タイプ付き表の中に行として保管する (タイプのそれぞれの属性は別々の列に保管される) か、列の中にオブジェクトとして保管する (タイプの属性はすべて 1 つの列に保管される) ことができます。タイプ付き表は識別のための属性を持っています。つまり、別の表は参照を使用して、インスタンスの属性にアクセスできるということです。他の表からインスタンスを参照する必要がある場合は、タイプ付き表を使用しなければなりません。他の表がオブジェクトを識別する必要がない場合は、オブジェクトを列に保管することについて考慮してください。
オブジェクトが表の中に行として保管されると、表の中のそれぞれの列には、オブジェクトの 1 つの属性が入ります。たとえば、人物のインスタンスを、名前の列と年齢の列を含む表に保管することができます。次の例は、Person というインスタンスを保管するための CREATE TABLE ステートメントです。
CREATE TABLE Person OF Person_t (REF IS Oid USER GENERATED)
Person というインスタンスを表に挿入するには、次の構文を使用します。
INSERT INTO Person (Oid, Name, Age) VALUES(Person_t('a'), 'Andrew', 29);
Oid | Name | Age | Address |
---|---|---|---|
a | Andrew | 29 |
プログラムは、タイプ付き表の列にアクセスすることによって、オブジェクトの属性にアクセスします。
UPDATE Person SET Age=30 WHERE Name='Andrew';
上記の UPDATE ステートメントの実行後、表は次のようになります。
Oid | Name | Age | Address |
---|---|---|---|
a | Andrew | 30 |
|
Employee_t という Person_t のサブタイプがあるので、 Employee_t のインスタンスを Person 表に保管することはできません。したがって、別の表に保管する必要があります。この表のことを副表 といいます。次の CREATE TABLE ステートメントは、 Person 表の下に Employee 副表を作成します。
CREATE TABLE Employee OF Employee_t UNDER Person INHERIT SELECT PRIVILEGES (SerialNum WITH OPTIONS NOT NULL, Dept WITH OPTIONS SCOPE BusinessUnit);
Employee 表への挿入は、次のようになります。
INSERT INTO Employee (Oid, Name, Age, SerialNum, Salary) VALUES (Employee_t('s'), 'susan', 39, 24001, 37000.48)
Oid | Name | Age | Address | SerialNum | Salary | Dept |
---|---|---|---|---|---|---|
s | Susan | 39 | 24001 | 37000.48 |
次の照会を実行すると、Susan の情報が戻されます。
SELECT * FROM Employee WHERE Name='susan';
これら 2 つの表に関する興味深い点は、
Person 表を対象として SQL ステートメントを実行するだけで、従業員と人物の両方のインスタンスにアクセスできるということです。この機能のことを代用性 といいます。これについては、構造型の付加的な特性で説明されています。タイプ階層の上位のインスタンスを含む表を対象として照会を実行すると、その階層の下位のタイプのインスタンスを自動的に入手できます。つまり、SELECT、UPDATE、および DELETE ステートメントにとって、
Person 表は論理的には次のように写るということです。
表 13. Person インスタンスと Employee インスタンスを含む Person 表
Oid | Name | Age | Address |
---|---|---|---|
a | Andrew | 30 | (ヌル) |
s | Susan | 39 | (ヌル) |
次の照会を実行すると、 Andrew (人物) と Susan (従業員) の両方のオブジェクト識別子と Person_t 情報を入手できます。
SELECT * FROM Person;
代用性の詳細については、構造型の付加的な特性を参照してください。
あるタイプ付き表の中にあるオブジェクトと別の表の中にあるオブジェクトとの間の関係を定義することができます。同じタイプ付き表の中にあるオブジェクト間の関係を定義することもできます。たとえば、部門というインスタンスが入っているタイプ付き表を定義してあるとします。 Employee 表の中で部門番号を保守するのではなく、 Employee 表の Dept 列の中に、 BusinessUnit 表の中の 1 つの部門を指す論理ポインターを入れることができます。これらのポインターのことを参照 といいます。これは 図 9 で図解されています。
図 9. Employee_t から BusinessUnit_t に対する構造型参照
![]() |
重要: 参照の機能は、参照制約の機能とは異なります。存在しない部門を参照することができるのです。部門と従業員との間の保全性を維持するのが重要である場合は、これら 2 つの表の間に参照制約を定義してください。参照の実際の機能は、複数の表の間の関係をナビゲートする照会を作成できるようにすることです。照会が行うことは、関係を逆参照して、ポインターによって指し示されているオブジェクトをインスタンス化することです。このアクションを実行するのに使用する演算子のことを逆参照 演算子といい、 -> で表します。
たとえば、Employee 表に対する次の照会では、逆参照演算子が使用されていて、 Dept 列から BusinessUnit 表へパスをたどるよう DB2 に伝えています。逆参照演算子は、Name 列の値を戻します。
SELECT Name, Salary, Dept->Name FROM Employee;
タイプ付き表に対する照会の作成方法の詳細については、 タイプ付き表の照会を参照してください。
オブジェクトを列に保管することは、 DB2 の組み込みデータ・タイプでは完全にモデル化することができない、ビジネス・オブジェクトについてのファクトをモデル化する必要がある場合に役立ちます。つまり、ビジネス・オブジェクト (従業員、部門など) をタイプ付き表に保管する場合でも、これらのオブジェクトは、構造型を使用すれば合理的にモデル化できる属性も持っている場合があるということです。
たとえば、アプリケーションが、住所の特定の部分にアクセスする必要があるとします。住所を構造化されていない文字ストリングとして保管するのではなく、 図 10 に示されているように構造化されたオブジェクトとして保管することができます。
![]() |
さらに、住所のタイプ階層を定義して、さまざまな国で使用されている住所のさまざまな形式をモデル化することができます。たとえば、郵便番号が含まれているアメリカの住所タイプと、区域属性が必要なブラジルの住所タイプの両方を含めたいとします。 Address_t タイプ階層は、構造型インスタンスの列への挿入で定義されています。
オブジェクトが列の値として保管されている場合は、表の行の中に保管されているオブジェクトのように、属性を外部的に表現することはできません。この場合、属性を操作するためのメソッドを使用する必要があります。 DB2 は、属性を戻すための observer メソッドと、属性を変更するための mutator メソッドの両方を生成します。次の例では、住所を変更するために 1 つの observer メソッドと、 Number 属性用と Street 属性用の 2 つの mutator メソッドを使用しています。
UPDATE Employee SET Address=Address..Number('4869')..Street('Appletree') WHERE Name='Franky' AND Address..State='CA';
上記の例では、UPDATE ステートメントの SET 文節は、タイプ Address_t のインスタンスの属性を更新するために、 Number および Street mutator メソッドを呼び出しています。 WHERE 文節は、Name 列の同一性比較と、 Address 列の State observer メソッドを呼び出す同一性比較という 2 つの述部によって、 UPDATE ステートメントの操作を制約しています。
同様に、Address_t タイプを使用して定義されている列には、アメリカ式の住所またはブラジル式の住所のインスタンスを入れることができます。
これに対して INSERT 操作は、 INSERT ステートメントで指定されている表だけに適用されます。 Employee 表に挿入を行うと、 Person 表階層に Employee_t オブジェクトが作成されます。
構造型をパラメーターとして関数に渡す場合、または構造型を関数からの結果として渡す場合にも、サブタイプのインスタンスを代用することができます。スカラー関数が Address_t というタイプのパラメーターを持っている場合は、 Address_t のインスタンスではなく、サブタイプの内の 1 つ (US_addr_t など) のインスタンスを渡すことができます。表関数は、構造型の列を戻すことはできません。
列または表が、あるタイプで定義されていても、そこに他のタイプのインスタンスが入っている場合があるので、定義に使用されるタイプと実行時に実際に戻されるインスタンスのタイプとを区別するのが重要な場合があります。列、行、または関数パラメーターの中の構造型の定義のことを静的タイプ といいます。構造型インスタンスの実際のタイプのことを動的タイプ といいます。動的タイプについての情報を受け取るために、アプリケーションは タイプに関連したその他の組み込み関数で説明されている TYPE_NAME、 TYPE_SCHEMA、および TYPE_ID 組み込み関数を使用します。