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言語リファレンス』を参照してください。
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_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.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_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);
オブジェクト・リレーショナル機能で表別名を指定する必要がある場合もあります。
2.1.8.1 表別名が必要な場合
参照解決で発生する問題を回避するために、表別名が必要となることがあります。
Oracle Databaseでは、内部取得および参照解決で発生する同様の問題を回避するために、表別名を使用して、サブプログラムまたはオブジェクトの属性へのドット表記による参照を修飾する必要があります。
内部取得とは、修飾されていない名前を使用することで発生する状況です。たとえば、depts
にassignment
列を追加した後、問合せの変更をしなかった場合、内側のSELECT
がdepts
表のassignment
列を使用するように、問合せが自動的に再コンパイルされます。
ドット表記法を使用せずに、オブジェクト表の最上位属性を直接参照する場合、表別名の使用は任意です。たとえば、次の文は、person_typ
オブジェクト型が含まれている2つの表を定義します。person_obj_table
はperson_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では、
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
文および副問合せに表別名を定義し、それらを使用して列参照を修飾することをお薦めします。
2.1.9 リモート・データベースでユーザー定義型を使用する際の制限事項
現在、オブジェクトまたはユーザー定義型(特に、PL/SQLパッケージ内部で宣言する型とは対照的な、SQL CREATE
TYPE
文を使用して宣言する型)は、1つのデータベース内部のみで有効です。
Oracle Databaseでは、データベース・リンクの使用に次のような制限があります。
-
リモート・データベースに接続して、リモート表に対してユーザー定義型またはオブジェクト
REF
の選択、挿入または更新を行うことはできません。オプションのキーワード
OID
を指定してCREATE
TYPE
文を使用し、1つのオブジェクト型を複数のデータベースで使用可能にするユーザー指定のオブジェクト識別子(OID)を作成できます。『Oracle Databaseデータ・カートリッジ開発者ガイド』の、オブジェクト型へのOIDの割当てに関する説明を参照してください。 -
PL/SQLコード内部でデータベース・リンクを使用して、リモート・ユーザー定義型のローカル変数を宣言することはできません。
-
PL/SQLリモート・プロシージャ・コールでユーザー定義型引数を送ったり、値を戻すことはできません。