ヘッダーをスキップ
Oracle® Databaseオブジェクト・リレーショナル開発者ガイド
12cリリース1 (12.1)
B72963-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

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

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


注意:

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

内容は次のとおりです。

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

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

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コレクションと何も要素を持たない空のコレクションは異なります。

文字長セマンティクス

一部の文字が複数のバイトで構成される場合でも、オブジェクト属性およびコレクション内で、キャラクタ・タイプ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_taboffice_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-4department_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;

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

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

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

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

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

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

名前解決

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

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);

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

表別名が必要な場合

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

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

ドット表記法を使用せずに、オブジェクト表の最上位属性を直接参照する場合は、表別名は任意で使用してください。たとえば、次の文は、person_typオブジェクト型が含まれている2つの表を定義します。person_obj_tableperson_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では、idnoperson_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の属性とメソッドを参照するメンバー・メソッドを記述するほうが簡単です。例2-8のコードおよびコメントは、属性hgtlenおよび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を除く)か、CHARACTERREALなどのANSI SQL型になります。『Oracle Database SQL言語クイック・リファレンス』の該当する項を参照してください。

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

マップ・メソッドは自動的にコールされ、obj_1 > obj_2のような比較や、行によるソートを必要とするDISTINCTGROUP BYUNIONおよび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オブジェクト型の継承

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

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


注意:

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

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

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

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

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

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

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

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

継承したメソッドを再定義しない場合、サブタイプには常に親タイプが持つ属性およびメソッドの同じコア・セットと、自身が追加する属性とメソッドが含まれます。person_typオブジェクト型がidnonameおよび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-14show()に注意してください。続くサブタイプの各例では、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-20person_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、つまりスーパータイプです。nameIdのみが表示されます。Joe Laneはstudent_typで、nameIdはスーパータイプの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メソッドを定義できます。

これらのメソッドの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_typcontactに挿入します。

例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言語リファレンス』

  • 『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_typperson_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表の代入可能な列pstudent_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 LEVELSIS 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 typeNOT 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_typtarget_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文は、列perscolperson_typの値を、employee_typの列empcolに設定します。perscolのそれぞれの値についての代入が成功するのは、この個人が従業員でもある場合です。個人が従業員ではない場合、TREATNULLを戻し、代入が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の場合、VALUEREFおよび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_refREF 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が学生でない個人の場合、またはpNULLの場合、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;

majorstudent_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言語リファレンス』を参照してください。