この章では、Oracle SQLオブジェクトを扱ううえでの基本的な情報について説明します。ここでは、オブジェクト型およびサブプログラムについて説明する他、共有ルート型から導出し、継承によって結合するオブジェクト型の階層を作成し扱う方法について説明します。
注意: 例の実行: 第2章の例を実行するためには、第1章で作成したオブジェクトの削除が必要な場合があります。 |
内容は次のとおりです。
この項では、次のSQLオブジェクト型および参照について説明します。
Oracle SQLオブジェクト型は、CREATE
TYPE
文で作成します。オブジェクト型の一般的な作成例を例2-1に示します。
関連項目:
|
自分自身の値が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コレクションと何も要素を持たない空のコレクションは異なります。
一部の文字が複数のバイトで構成される場合でも、オブジェクト属性およびコレクション内で、キャラクタ・タイプ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;
Oracle Databaseでは、SCOPE
句または参照制約句を使用して、REF
型の列または属性を制約なしまたは制約付きにすることが可能です。制約なしのREF
列には、対応するオブジェクト型のオブジェクト表に含まれている行オブジェクトに対するオブジェクト参照を格納できます。
Oracle Databaseは、そのような列に格納されたオブジェクト参照が、有効な既存の行オブジェクトを指すことを保証しません。したがって、REF
列に、既存の行オブジェクトを指していないオブジェクト参照が含まれることがあります。このようなREF
値は、参照先がない参照と呼ばれます。
SCOPE
制約は、特定のオブジェクト表に適用できます。SCOPE
制約が付いた列に格納されたすべてのREF
値は、SCOPE
句で指定された表の行オブジェクトを指します。ただし、REF
値には参照先がない場合があります。
REF
列には、外部キーの指定に類似したREFERENTIAL
制約を指定することもできます。参照制約のルールは、そのような列に適用されます。つまり、このような列に格納されたオブジェクト参照は、指定されたオブジェクト表内の有効な既存の行オブジェクトを指す必要があります。
REF
列には、PRIMARY
KEY
制約を指定できません。ただし、NOT
NULL
制約は指定できます。
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
属性を参照する正しい方法と、誤った方法が示されています。
注意: これらの文は、この章の他の例とは関連していません。 |
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
の属性とメソッドを参照するメンバー・メソッドを記述するほうが簡単です。例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-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を使用して、他の言語で作成された外部のサブプログラムを起動できます。これにより、これらの言語の長所や機能を活用できます。
SQLオブジェクト継承は、型階層を構成するオブジェクト型の系図に基づいています。型階層は、スーパータイプと呼ばれる親オブジェクト型と、親から導出されたサブタイプと呼ばれる1つ以上のレベルの子オブジェクト型で構成されます。
継承は、階層内のサブタイプを対応するスーパータイプに接続するメカニズムです。サブタイプは、その親タイプの属性およびメソッドを自動的に継承します。また、継承リンクも保持されます。サブタイプは、親の属性またはメソッドの変更を自動的に取得します。スーパータイプの属性またはメソッドが更新されると、サブタイプにおいてもこの更新が行われます。
注意: 単一継承のみがサポートされています。したがって、サブタイプは1つのみのスーパータイプから直接導出できます。複数のスーパータイプから導出することはできません。 |
型階層内でオブジェクト型を使用すると、顧客などのエンティティをモデル化したり、元の型を基にして顧客の特化された様々なサブタイプを定義することができます。このように定義した後、階層に対して操作を行い、それぞれの型を実装させ、専用の方法で操作を実行できます。
この項では、次の内容を説明します。
サブタイプは、スーパータイプから直接または他のサブタイプを介して間接的に導出できます。スーパータイプは、兄弟関係にあるサブタイプを複数持つことができますが、サブタイプが持つことができる直系の親スーパータイプは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
サブタイプの属性またはメソッドは、次の方法で特化します。
親スーパータイプが持たない新しい属性を追加します。
たとえば、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
(デフォルト)は、スーパータイプのメソッドをオーバーライドできることを意味します。
オブジェクトの型およびメソッドの定義では、例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;
出力は次のようになります。
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
メソッド
インスタンス化不可のメソッドは、プレースホルダの役目を果します。これは宣言されますが、型の中に実装されません。すべてのサブタイプにおいてそれぞれ独自の方法でメソッドをオーバーライドする場合に、インスタンス化不可のメソッドを定義します。この場合、スーパータイプにメソッドを定義しても有益ではありません。
インスタンス化不可のメソッドを含む型は、例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(),
...);
メソッドのオーバーライドには、次の制限事項があります。
オーバーライドできるメソッドは、スーパータイプでFINALとして宣言されていないもののみです。
オーダー・メソッドが出現する可能性があるのは、型階層のルート型のみで、サブタイプで再定義(オーバーライド)することはできません。
サブタイプの静的メソッドにより、スーパータイプのメンバー・メソッドを再定義することはできません。
サブタイプのメンバー・メソッドにより、スーパータイプの静的メソッドを再定義することはできません。
オーバーライドされているメソッドが、いずれかのパラメータのデフォルト値を持つ場合は、そのパラメータのデフォルト値と同じものを、オーバーライドするメソッドに持たせる必要があります。
動的メソッド・ディスパッチとは、現在の型または指定された型から上方向に型階層を調べて、実行時にメソッド・コールを最も近い実装にディスパッチする方法のことです。この機能は、メンバー・メソッドをオーバーライドするときにのみ使用可能であり、静的メソッドには適用されません。
メソッドのオーバーライドにより、型階層で同じメソッドの複数の実装を定義できます。次に示すellipse_typ
型、circle_typ
型、sphere_typ
型の階層の中では、それぞれの型が異なる方法でcalculate
メソッドを定義できます。
これらのメソッドの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」を参照してください。
例2-24に示すように、OBJECT_VALUE
およびOBJECT_ID
疑似列によって、オブジェクト表内の代入可能な行の値およびオブジェクト識別子(OID)にアクセスし、識別できます。
関連項目: これらの疑似列の詳細は、『Oracle Database SQL言語リファレンス』を参照してください |
サブタイプは、型がスーパータイプの型である属性を持つことが可能です。次に例を示します。
例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 ...
「新しい表での代入性の無効化」を参照してください。
サブタイプを作成すると、スーパータイプの代入可能な列をすでに持つ表に、新しいサブタイプも格納できるようになります。つまり、サブタイプの作成には、このような表の有無が影響します。このような表が存在する場合、代入可能なサブタイプ(表の制約に違反しないサブタイプ)のみ作成できます。
次の例で、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; /
次に、オブジェクトやオブジェクトの参照を扱う際に特に役立つファンクションや演算子を示します。
使用例は、このマニュアルの他の章でも示しています。
PL/SQLの場合、VALUE
、REF
およびDEREF
ファンクションが現れるのは、SQL文の中のみです。SQLファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
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
式は、ネストしたカーソルを戻します。この形式の式は、PL/SQLのREF
CURSOR
と同等で、REF
CURSOR
引数としてファンクションに渡すことが可能です。
SQL CURSOR
式の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
SQL文のDEREF
ファンクションは、REF
に対応するオブジェクト・インスタンスを戻します。DEREF
により戻されるオブジェクト・インスタンスは、REF
の宣言された型か、またはこの型のサブタイプになる可能性があります。
次に示す文は、表contact_ref
からperson_typ
オブジェクトを戻します。
「REFの参照解除」を参照してください。SQL DEREF
ファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
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言語リファレンス』を参照してください。
SQL文のREF
ファンクションは、オブジェクト表またはビューの相関名(または表別名)を引数としてとり、その表またはビューからオブジェクト・インスタンスの参照(REF
)を戻します。REF
ファンクションにより、表またはビューの宣言された型のオブジェクトの参照、またはその型のサブタイプのオブジェクトの参照が戻せます。たとえば、次の文は、idno
属性が12である学生や従業員の参照など個人全員の参照を戻します。
SQL REF
ファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
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
を取得します。インスタンスのそれぞれが、異なる型を持ちます。
型判別式の列および他の非表示列の詳細は、「代入可能な列およびオブジェクト表の非表示列」を参照してください。SQL SYS
TYPEID
ファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
テーブル・ファンクションとは、物理データベース表のように問い合せたり、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
はSQLでNULL
を戻します。
TREAT
は、主に次の2つの目的で使用します。
ナローイング代入で、階層内のさらに特化された型の変数に式が代入できるように、式のタイプを変更するため(スーパータイプの値をサブタイプに設定するため)。
行または列の宣言された型のサブタイプの属性またはメソッドにアクセスするため。
型T
の代入可能なオブジェクト表または列には、T
のすべてのサブタイプのすべての属性についての非表示列があります。これらの非表示列にはサブタイプの属性データが含まれますが、DESCRIBE
文でこれらの非表示列をリストすることはできません。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
の最も重要な使用方法です。次の問合せでは、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言語リファレンス』を参照してください。
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言語リファレンス』を参照してください。