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

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

内容は次のとおりです。

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

関連項目:

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

自分自身の値がNULLであるオブジェクトを、アトミックNULLといいます。

アトミックNULLオブジェクトは、すべての属性の値がNULL値であるオブジェクトとは異なります。

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

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

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

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

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

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

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

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

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

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

「PL/SQLでの未初期化オブジェクトの処理規則」を参照してください

2.1.2 文字長セマンティクス

一部の文字が複数のバイトで構成される場合でも、オブジェクト属性およびコレクション内で、キャラクタ・タイプ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グローバリゼーション・サポート・ガイド』を参照してください。

2.1.3 単一の制約を使用したオブジェクト表の定義

他の表と同様に、オブジェクト表にも制約を定義できます。

参照範囲が制限されていない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.1.4 複数の制約を使用したオブジェクト表の定義

複数の制約を使用してオブジェクト表を定義できます。

複数の制約を使用してオブジェクト表を定義できます。

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

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

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

「オブジェクトに対する制約」を参照してください

2.1.5 オブジェクト表の索引の定義

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

列オブジェクトのリーフ・レベル・スカラー属性に索引を定義します。有効範囲付きREFの場合、REF型の属性または列にのみ索引を定義できます。

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

この例2-5では、列オブジェクトdept_addrのリーフ・レベル・スカラー属性であるcityに索引を作成します。

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

ネストした表の索引の例は、「ネストした表の要素の格納」を参照してください。

2.1.6 オブジェクト表のトリガーの定義

オブジェクト表には、他の表と同様に、トリガーを定義できます。

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

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

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

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

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

「変更および妥当性チェックを制御するINSTEAD OFトリガー」を参照してください

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

REF型の列および属性のルールは、制約を使用することで強制できます。

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

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

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

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

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

2.1.8 名前解決

Oracle Databaseでは名前を解決する方法が複数あります。

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

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

2.1.8.1 表別名が必要な場合

参照解決で発生する問題を回避するために、表別名が必要となることがあります。

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

内部取得とは、修飾されていない名前を使用することで発生する状況です。たとえば、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文および副問合せに表別名を定義し、それらを使用して列参照を修飾することをお薦めします。

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

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

Oracle Databaseでは、データベース・リンクの使用に次のような制限があります。

  • リモート・データベースに接続して、リモート表に対してユーザー定義型またはオブジェクトREFの選択、挿入または更新を行うことはできません。

    オプションのキーワードOIDを指定してCREATE TYPE文を使用し、1つのオブジェクト型を複数のデータベースで使用可能にするユーザー指定のオブジェクト識別子(OID)を作成できます。『Oracle Databaseデータ・カートリッジ開発者ガイド』の、オブジェクト型へのOIDの割当てに関する説明を参照してください。

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

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