この章では、基礎となるリレーショナル・データの構造を変更することなく、オブジェクト指向アプリケーションを作成する方法を示します。
内容は次のとおりです。
ビューが仮想表であることと同様、オブジェクト・ビューは仮想的なオブジェクト表です。ビューの各行はオブジェクトであるため、メソッドのコール、ドット表記法を使用したオブジェクト属性へのアクセスおよびオブジェクトを指すREF
の作成が可能です。
オブジェクト指向アプリケーションは、既存の表を別の物理構造に変換せずに実行できます。このためには、オブジェクト・ビューを使用して、オブジェクト指向アプリケーションのプロトタイプを作成したり、オブジェクト指向アプリケーションに切り替えることができます。ビューの中のデータはリレーショナル表から取り出すことができ、オブジェクト表として定義されているかのようにアクセスできるためです。
オブジェクト・ビューは、リレーショナル・ビューのように使用し、目的のデータのみ画面上に表示できます。たとえば、給料など機密データを除いて、従業員表の特定のデータを表示するオブジェクト・ビューが作成できます。
オブジェクト・ビューの使用によって、パフォーマンスが向上します。オブジェクト・ビューの1行を構成するリレーショナル・データは、1単位としてネットワークを横断するため、ラウンドトリップが大幅に削減されます。
リレーショナル・データは、クライアント側のオブジェクト・キャッシュにフェッチでき、Cの構造体、C++またはJavaクラスにマップすることもできるので、3GLアプリケーションで固有のクラスのように操作できます。また、複雑なオブジェクト検索のようなオブジェクト指向機能をリレーショナル・データとともに使用することもできます。
リレーショナル・データからオブジェクトを合成することによって、新しい方法でデータを問い合せることができます。複数の表との複雑な結合を記述するかわりに、オブジェクトの参照解除を利用することで複数の表からデータを表示できます。
オブジェクト・ビューからオブジェクト・データを確保し、クライアント側のオブジェクト・キャッシュ内でそのデータを使用できます。オブジェクト・キャッシュ上に確保された、これらの合成されたオブジェクトを、専用のオブジェクト検索メカニズムにより取り出すことで、ネットワーク通信量を削減できます。
ビュー内部にオブジェクト・モデルを作成しながら、モデル開発が継続できるという、優れた柔軟性が得られます。オブジェクト型を変更する必要がある場合、無効なビューを新しい定義に簡単に置換できます。
ビューの中のオブジェクトを使用することで、基礎となる記憶域メカニズムの特性が制限されることはありません。同様に、現行のテクノロジによって制限されることもありません。たとえば、パラレル化およびパーティション化されたリレーショナル表からオブジェクトを合成することもできます。
基礎となる同じデータから異なる複合データ・モデルを作成できます。
関連項目:
|
オブジェクト・ビューを定義する手順は、次のとおりです。
既存のリレーショナル表の列にそれぞれ対応するデータ型の属性を持つオブジェクト型を定義します。
リレーショナル表からデータを抽出する方法を指定する問合せを作成します。オブジェクト型の属性と同じ順序で、リレーショナル表の列を指定します。
基礎となるデータの属性に基づいて、一意の値を指定します。これは、ビュー内のオブジェクトを指すポインタ(REF
)を作成するためのオブジェクト識別子となります。既存の主キーを使用することもできます。
オブジェクト型の属性が既存の表の列に正確に対応していないオブジェクト・ビューを更新するには、次の手順を実行する必要があることがあります。
アプリケーション・プログラムがオブジェクト・ビューのデータを更新するときに、Oracleに実行させるINSTEAD
OF
トリガー・プロシージャを作成します。「オブジェクト・ビューの更新」を参照してください。
これで、オブジェクト・ビューをオブジェクト表と同様に使用できます。
例6-1のSQL文は、各行がemployee_t
型のオブジェクトであるオブジェクト・ビューを定義しています。
例6-1 オブジェクト・ビューの作成
CREATE TABLE emp_table (
empnum NUMBER (5),
ename VARCHAR2 (20),
salary NUMBER (9,2),
job VARCHAR2 (20));
CREATE TYPE employee_t AS OBJECT (
empno NUMBER (5),
ename VARCHAR2 (20),
salary NUMBER (9,2),
job VARCHAR2 (20));
/
CREATE VIEW emp_view1 OF employee_t
WITH OBJECT IDENTIFIER (empno) AS
SELECT e.empnum, e.ename, e.salary, e.job
FROM emp_table e
WHERE job = 'Developer';
insert into emp_table values(1,'John',1000.00,'Architect');
insert into emp_table values(2,'Robert',900.00,'Developer');
insert into emp_table values(3,'James',2000.00,'Director');
select * from emp_view1;
EMPNO ENAME SALARY JOB
---------- -------------------- ---------- --------------------
2 Robert 900 Developer
リレーショナル表のempnum
列のデータにアクセスするには、オブジェクト型のempno
属性にアクセスします。
オブジェクト・ビューの行にあるデータが複数の表から取り出される可能性もありますが、その場合もオブジェクト・ビューは1つの操作のみでネットワークを横断します。クライアント側のオブジェクト・キャッシュの中では、インスタンスはCまたはC++の構造体として、またはPL/SQLオブジェクト変数として現れます。このインスタンスを、他のすべてのシステム固有の構造体と同様に操作することもできます。
SQL文の中で、オブジェクト・ビューはオブジェクト表と同じ方法で参照できます。たとえば、オブジェクト・ビューが現れる可能性があるのは、SELECT
構文のリスト、UPDATE-SET
句またはWHERE
句の中です。
また、オブジェクト・ビューにオブジェクト・ビューを定義することもできます。
オブジェクト表からオブジェクトに対して使用するものと同じOCIコールを使用して、クライアント側のオブジェクト・ビューのデータにアクセスできます。たとえば、REF
を確保するためにOCIObjectPin()
を、また、オブジェクトをサーバーにフラッシュするためにOCIObjectFlush()
を使用できます。オブジェクト・ビューのオブジェクトをデータベースに更新またはフラッシュすると、データベースでオブジェクト・ビューが更新されます。
関連項目: OCIコールの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。 |
オブジェクト型は、他のオブジェクト型を属性として自身にネストさせることができます。
オブジェクト・ビューの基になっているオブジェクト型が、それ自身がオブジェクト型である属性を持っている場合は、オブジェクト・ビューを作成する処理の一部として、この属性用の列オブジェクトを用意する必要があります。属性型の列オブジェクトがリレーショナル表にすでに存在する場合は、この列オブジェクトを選択するのみですみます。存在しない場合は、ビューの主オブジェクト・インスタンスを合成する場合と同様に、基礎となるリレーショナル・データからオブジェクト・インスタンスを合成する必要があります。これらのオブジェクトを合成または作成するには、オブジェクト型の各コンストラクタ・メソッドをコールしてオブジェクト・インスタンスを作成しますが、それらの属性には、コンストラクタで指定したリレーショナル列からデータを移入できます。
たとえば、例6-2の部門表dept
について考えてみます。住所が部門オブジェクト内部のオブジェクトになっているオブジェクト・ビューを作成します。これにより、住所オブジェクト用の再利用可能なメソッドを定義し、様々なアドレスに使用できるようになります。
まず住所オブジェクト用と部門オブジェクト用の型を作成してから、部門番号、名前および住所を含むビューを作成します。リレーショナル表の列から、address
オブジェクトが作成されます。
例6-2 ネストしたオブジェクト型を持つビューの作成
CREATE TABLE dept (
deptno NUMBER PRIMARY KEY,
deptname VARCHAR2(20),
deptstreet VARCHAR2(20),
deptcity VARCHAR2(10),
deptstate CHAR(2),
deptzip VARCHAR2(10));
CREATE TYPE address_t AS OBJECT (
street VARCHAR2(20),
city VARCHAR2(10),
state CHAR(2),
zip VARCHAR2(10));
/
CREATE TYPE dept_t AS OBJECT (
deptno NUMBER,
deptname VARCHAR2(20),
address address_t );
/
CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER (deptno) AS
SELECT d.deptno, d.deptname,
address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS
deptaddr
FROM dept d;
insert into dept values(1,'Sales','500 Oracle pkwy','Redwood S','CA','94065');
insert into dept values(2,'ST','400 Oracle Pkwy','Redwood S','CA','94065');
insert into dept values(3,'Apps','300 Oracle pkwy','Redwood S','CA','94065');
select * from dept_view;
DEPTNO DEPTNAME
---------- --------------------
ADDRESS(STREET, CITY, STATE, ZIP)
----------------------------------------------------------------------------------
1 Sales
ADDRESS_T('500 Oracle pkwy', 'Redwood S', 'CA', '94065')
2 ST
ADDRESS_T('400 Oracle Pkwy', 'Redwood S', 'CA', '94065')
3 Apps
ADDRESS_T('300 Oracle pkwy', 'Redwood S', 'CA', '94065')
オブジェクトのコンストラクタからNULLが戻されることはありません。したがって、前述のビューにおいて、リレーショナル表の中のcity、streetなどの列がすべてNULLであっても、アドレス・オブジェクトがNULLになることはありません。リレーショナル表には、部門の住所がNULLかどうかを指定する列はありません。
DECODE
ファンクションまたは他のファンクションを使用して、NULLまたは構成されたオブジェクトのいずれかを返すことにより、NULLのdeptstreet
列によって住所全体がNULLであることを表すことができます。
例6-3 オブジェクト・ビューにおけるNULLオブジェクトの識別
-- Requires Ex. 6-2 CREATE OR REPLACE VIEW dept_view AS SELECT d.deptno, d.deptname, DECODE(d.deptstreet, NULL, NULL, address_t(d.deptstreet, d.deptcity, d.deptstate, d.deptzip)) AS deptaddr FROM dept d;
部門の住所はリレーショナル表の中の列と直接対応していないため、この方法を使用すると、ビューを介して部門の住所を直接更新できなくなります。この方法ではなく、ビュー上にINSTEAD
OF
トリガーを定義して、この列の更新を操作します。
ネストした表およびVARRAY
のコレクションはどちらも、ビューの列になる場合があります。これらのコレクションは、基礎となるコレクション列から選択するか、または副問合せを使用して合成できます。CAST-MULTISET
演算子によって、これらのコレクションを合成します。
この項の内容は次のとおりです。
最初に例6-1および例6-2を使用することで、emp
リレーショナル表に存在する各従業員は例6-4の構造を持ちます。このリレーショナル表を使用すると、部門番号、名前、住所および部門に所属する従業員のコレクションを持つdept_view
を構成できます。
まず、従業員型employee_t
用のネストした表型を定義します。次に、部門番号、名前、住所、および従業員のネストした表を持つ部門型を定義します。最後に、オブジェクト・ビューdept_view
を定義します。
例6-4 シングルレベル・コレクションを持つビューの作成
-- Requires Ex. 6-1 and Ex. 6-2 CREATE TABLE emp ( empno NUMBER PRIMARY KEY, empname VARCHAR2(20), salary NUMBER, job VARCHAR2 (20), deptno NUMBER REFERENCES dept(deptno)); CREATE TYPE employee_list_t AS TABLE OF employee_t; -- nested table / CREATE TYPE dept_t AS OBJECT ( deptno NUMBER, deptname VARCHAR2(20), address address_t, emp_list employee_list_t); / CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER (deptno) AS SELECT d.deptno, d.deptname, address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr, CAST( MULTISET ( SELECT e.empno, e.empname, e.salary, e.job FROM emp e WHERE e.deptno = d.deptno) AS employee_list_t) AS emp_list FROM dept d; insert into dept values(100,'ST','400 Oracle Pkwy','Redwood S','CA',94065); insert into dept values(200,'Sales','500 Oracle Pkwy','Redwood S','CA',94065); insert into emp values(1,'John',900,'Developer1',100); insert into emp values(2,'Robert',1000,'Developer2',100); insert into emp values(3,'Mary', 1000,'Apps1',200); insert into emp values(4,'Maria',1500,'Developer3',200); select * from dept_view where deptno = 100; DEPTNO DEPTNAME ---------- -------------------- ADDRESS(STREET, CITY, STATE, ZIP) -------------------------------------------------------------------------------- EMP_LIST(EMPNO, ENAME, SALARY, JOB) -------------------------------------------------------------------------------- 100 ST ADDRESS_T('400 Oracle Pkwy', 'Redwood S', 'CA', '94065') EMPLOYEE_LIST_T(EMPLOYEE_T(1, 'John', 900, 'Developer1'), EMPLOYEE_T(2, 'Robert' , 1000, 'Developer2')) select emp_list from dept_view where deptno = 100; EMP_LIST(EMPNO, ENAME, SALARY, JOB) -------------------------------------------------------------------------------- EMPLOYEE_LIST_T(EMPLOYEE_T(1, 'John', 900, 'Developer1'), EMPLOYEE_T(2, 'Robert' , 1000, 'Developer2'))
CAST-MULTISET
ブロック内のSELECT
副問合せにより、現在の部門に所属する従業員のリストが選択されます。MULTISET
キーワードは、これが単一の値とは対照的なリストであることを示します。CAST
演算子は、結果セットを適切な型にキャスト(型変換)します。この場合は、ネストした表型employee_list_t
にキャストします。
このビューへの問合せでは、それぞれの部門行に、部門番号、名前、住所オブジェクトおよびその部門に所属する従業員のコレクションが入っている部門リストが取得できます。
マルチレベル・コレクションもシングルレベル・コレクションも、オブジェクト・ビューで同じ方法で作成し、使用します。異なるのは、マルチレベル・コレクションで、別のレベルのコレクションを作成する必要がある点のみです。
例6-5では、マルチレベル・コレクションが含まれているオブジェクト・ビューを作成します。このビューは、コレクションが何も入っていないフラットなリレーショナル表に基づいています。オブジェクト・ビューを作成する準備作業として、この例で使用するオブジェクト型とコレクション型を作成します。それぞれのリレーショナル表と対応するように、オブジェクト型(たとえば、emp_t
)を定義し、その属性の型は、それぞれの表列の型と対応させます。また、従業員型はプロジェクトのネストした表(属性)を持ち、部門型は従業員のネストした表(属性)を持ちます。後者のネストした表は、マルチレベル・コレクションです。CREATE
VIEW
文の中でCAST-MULTISET
演算子を使用して、コレクションを作成します。
例6-5 マルチレベル・コレクションを持つビューの作成
CREATE TABLE depts ( deptno NUMBER, deptname VARCHAR2(20)); CREATE TABLE emps ( ename VARCHAR2(20), salary NUMBER, deptname VARCHAR2(20)); CREATE TABLE projects ( projname VARCHAR2(20), mgr VARCHAR2(20)); CREATE TYPE project_t AS OBJECT ( projname VARCHAR2(20), mgr VARCHAR2(20)); / CREATE TYPE nt_project_t AS TABLE OF project_t; / CREATE TYPE emp_t AS OBJECT ( ename VARCHAR2(20), salary NUMBER, deptname VARCHAR2(20), projects nt_project_t ); / CREATE TYPE nt_emp_t AS TABLE OF emp_t; / CREATE TYPE depts_t AS OBJECT ( deptno NUMBER, deptname VARCHAR2(20), emps nt_emp_t ); / CREATE VIEW v_depts OF depts_t WITH OBJECT IDENTIFIER (deptno) AS SELECT d.deptno, d.deptname, CAST(MULTISET(SELECT e.ename, e.salary, e.deptname, CAST(MULTISET(SELECT p.projname, p.mgr FROM projects p WHERE p.mgr = e.ename) AS nt_project_t) FROM emps e WHERE e.deptname = d.deptname) AS nt_emp_t) FROM depts d;
オブジェクト・ビューの中で、行オブジェクトを指すポインタ(REF
)を作成できます。ビューのデータは永続的に格納されるわけではないため、オブジェクト識別子として使用される個々の値を指定する必要があります。オブジェクト識別子を使用すると、オブジェクト・ビューにおけるオブジェクトを、オブジェクト・キャッシュ上で参照し、確保することができます。
このビューがオブジェクト表またはオブジェクト・ビューに基づいている場合には、すでに各行に対応付けられたオブジェクト識別子があり、これを再利用できます。このためには、WITH
OBJECT
IDENTIFIER
句を省略するか、またはWITH
OBJECT
IDENTIFIER
DEFAULT
句を指定します。
ただし、行オブジェクトをリレーショナル・データから合成する場合は、他の値セットを選択する必要があります。
主キーに基づいたオブジェクト識別子を指定できます。この場合、行オブジェクトを識別する一意のキーの集合が、そのオブジェクトの識別子になります。値が重複すると、オブジェクト参照時に問題が発生することもあるため、これらの値はビューから選択された行内で一意である必要があります。
WITH
OBJECT
IDENTIFIER
句を使用して作成されたオブジェクト・ビュー
WITH
OBJECT
IDENTIFIER
句を使用して作成されたオブジェクト・ビューは、主キーから導出されたオブジェクト識別子を持ちます。
たとえば、「オブジェクト・ビューのシングルレベル・コレクション」で説明したオブジェクト型dept_t
およびオブジェクト・ビューdept_view
の定義について考えます。
基礎となるリレーショナル表にdeptno
が主キーとして入っているため、各部門行は一意の部門番号を持ちます。このビューでは、deptno
列がオブジェクト型のdeptno
属性になります。ビュー・オブジェクト内でdeptno
が一意であることがわかれば、これをオブジェクト識別子として指定できます。
WITH
OBJECT
IDENTIFIER
DEFAULT
句を使用して作成されたオブジェクト・ビュー
WITH
OBJECT
IDENTIFIER
DEFAULT
句を指定した場合、オブジェクト識別子は、基礎となる表またはビュー定義に応じてはシステム生成または主キー・ベースになります。
この例6-2と例6-4の連結された例グループにおいて、dept_view
ビューから選択された各オブジェクトは、部門番号の値から導出された一意のオブジェクト識別子を持ちます。リレーショナルの場合、従業員表emp
の外部キーdeptno
は、部門表dept
の主キー値deptno
と一致します。主キー値はdept_view
内にオブジェクト識別子を作成するため、emp_view
の外部キー値はdept_view
の主キー値の参照を作成できます。
主キーのオブジェクト参照を合成するには、MAKE_REF
演算子を使用します。この演算子は、参照がポイントするビューまたは表の名前および外部キー値のリストをとり、参照されたビューの中の特定のオブジェクトと一致するような参照のオブジェクト識別子部分を作成します。
例6-6では、まず従業員型emp_t
を作成し、次にその型に基づいたビューを作成することにより、従業員の番号、名前、給料、および所属部門の参照を持つemp_view
ビューを作成します。
例6-6 ビューでのオブジェクトへの参照の作成
-- Requires Ex. 6-2 and Ex. 6-4 -- if you have previously created emp_t, you must drop it CREATE TYPE emp_t AS OBJECT ( empno NUMBER, ename VARCHAR2(20), salary NUMBER, deptref REF dept_t); / CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(empno) AS SELECT e.empno, e.empname, e.salary, MAKE_REF(dept_view, e.deptno) FROM emp e;
ビューの中のdeptref
列に、部門の参照が格納されます。次の簡単な問合せでは、Redwood S市にある部門のすべての従業員を取り出します。
SELECT e.empno, e.salary, e.deptref.deptno FROM emp_view e WHERE e.deptref.address.city = 'Redwood S'; EMPNO SALARY DEPTREF.DEPTNO ---------- ---------- -------------- 2 1000 100 1 900 100 4 1500 200 3 1000 200
次のようにMAKE_REF
のかわりにREF
修飾子を使用してemp_view
を作成しても、dept_view
オブジェクトの参照が取得できる点に注意してください。
例6-7 REFを使用したオブジェクトの問合せ参照
-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6
CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(empno)
AS SELECT e.empno, e.empname, e.salary, REF(d)
FROM emp e, dept_view d
WHERE e.deptno = d.deptno;
例6-7では、dept_view
とemp
表はdeptno
キーで結合されます。
例6-6のようにREF
修飾子のかわりにMAKE_REF
演算子を使用すると、循環参照を作成できるというメリットがあります。たとえば、従業員の部門への参照を持つ従業員のビューを作成する一方で、その部門に所属している従業員への参照のリストを持つ部門のビューを作成することができます。
オブジェクト・ビューが主キー・ベースのオブジェクト識別子を持つ場合、このようなビューへの参照は主キー・ベースになることに注意してください。一方、システム生成のオブジェクト識別子を持つビューへの参照は、システム生成のオブジェクト参照になります。この違いが関係するのは、OCIオブジェクト・キャッシュでオブジェクト・インスタンスを作成し、新しく作成したオブジェクトの参照を取得する必要がある場合のみです。
合成オブジェクトの場合と同様、永続的に格納される参照をビュー列として選択し、これらを問合せで透過的に使用できます。ただし、ビュー・オブジェクトに対するオブジェクト参照を永続的に格納することはできません。
オブジェクトを持つビューを使用して、逆リレーションシップをモデル化できます。
1対1リレーションシップは、オブジェクトの逆参照を使用してモデル化できます。たとえば、各従業員が専用のデスクトップ・コンピュータを持っているとしましょう。リレーショナル・モデルであれば、コンピュータ表から従業員表へ、または逆の方向で外部キーを使用して、1対1リレーションシップを獲得します。ビューを使用すると、従業員からコンピュータ・オブジェクトへのオブジェクト参照や、コンピュータ・オブジェクトから従業員の参照が行えるように、オブジェクトをモデル化できます。
1対多および多対1リレーションシップ
1対多リレーションシップ(または多対1リレーションシップ)は、オブジェクト参照を使用するか、オブジェクトを埋め込むことでモデル化できます。1対多リレーションシップは、オブジェクトのコレクションまたはオブジェクト参照のコレクションを持つことでモデル化できます。多対1リレーションシップは、オブジェクト参照を使用してモデル化できます。
部門対従業員のケースを検討してみましょう。基礎となるリレーショナル・モデルでは、外部キーが従業員表の中にあります。部門と従業員のリレーションシップは、ビュー内のコレクションを使用してモデル化できます。部門ビューに従業員のコレクションを持たせ、従業員ビューに部門の参照を持たせることができます(または部門値がインライン化できます)。これにより、前方リレーションシップ(従業員から部門へ)と逆リレーションシップ(部門から従業員リストへ)の両方が得られます。また、部門ビューに、従業員オブジェクトを埋め込むかわりに、従業員オブジェクトの参照のコレクションを持たせることも可能です。
オブジェクト表に使用するSQL DMLと同じものを使用して、オブジェクト・ビューのデータを更新、挿入および削除できます。あいまいな表現がなければ、オブジェクト・ビューの実表が更新されます。
ビューは常に直接更新できるわけではありません。
ビューの問合せに結合、集合演算子、集計ファンクション、GROUP BY
またはDISTINCT
句が含まれている場合、ビューの直接更新はできません。ビューの問合せで、ビューの列が疑似列または式に基づいている場合も、ビューの個々の列を直接更新することはできません。
ビューが直接更新できなくても、INSTEAD OF
トリガーを使用して、間接的に更新できます。この操作を行うには、ビューに対して実行するそれぞれのDML文に、INSTEAD
OF
トリガーを定義します。INSTEAD
OF
トリガーには、目的の変更をビューで行うために、ビューの基礎となる表に対して実行する必要のある操作をプログラムします。この後、INSTEAD
OF
トリガーが定義されたDML文を発行すると、関連するトリガーが透過的に実行されます。
注意: オブジェクト・ビュー階層では、UPDATE 文およびDELETE 文は、SELECT 文と同様に多相性を伴って動作します。つまり、ビューに対して実行されたUPDATE またはDELETE 文で抽出される行の集合には、指定されたビューのすべてのサブビューにある修飾行も明示的に含まれます。 |
たとえば、Person_v
から全員を削除する次の文により、Student_v
から学生全員が削除され、Employee_v
ビューから従業員全員が削除されます。
DELETE FROM Person_v;
サブビューを除外し、影響する行の対象を、指定されたビューに存在する人たちに限定するには、ONLY
キーワードを使用します。たとえば、次の文は個人のみ更新し、従業員または学生は更新しません。
UPDATE ONLY(Person_v) SET address = ...
ネストした表を更新するには、新しい要素を挿入したり、既存の要素を更新または削除します。ビューの場合と同様に、仮想または合成のネストした表列は、通常は更新できません。この問題に対処するために、この列の上にINSTEAD
OF
トリガーを作成できます。
(ビューの)ネストした表列に対して定義されたINSTEAD
OF
トリガーは、列を変更するときに起動します。親である行の更新によってコレクション全体が置換される場合は、ネストした表列のINSTEAD
OF
トリガーは起動されないため注意してください。
INSTEAD
OF
トリガーを使用することで、他の方法では更新できない複雑なビューを更新できます。また制約の施行、権限のチェック、DML文の妥当性チェックにも、このトリガーを使用できます。これらのトリガーを使用すると、オブジェクト・ビューを介して作成されたオブジェクトに挿入、更新および削除が行われた結果としての変更を制御できます。
たとえば、ある部門の従業員の数を10以下とするという条件を施行する場合は、従業員ビュー用のINSTEAD
OF
トリガーを記述できます。ビューは更新できるため、DML文の実行にトリガーは必要ありませんが、制約を施行するにはトリガーが必要です。
例6-8に、SQL文を使用してトリガーを実装する方法を示します。
例6-8 ビューのINSTEAD OFトリガーの作成
-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6 CREATE TRIGGER emp_instr INSTEAD OF INSERT on emp_view FOR EACH ROW DECLARE dept_var dept_t; emp_count integer; BEGIN -- Enforce the constraint -- First get the department number from the reference UTL_REF.SELECT_OBJECT(:NEW.deptref, dept_var); SELECT COUNT(*) INTO emp_count FROM emp WHERE deptno = dept_var.deptno; IF emp_count < 9 THEN -- Do the insert INSERT INTO emp (empno, empname, salary, deptno) VALUES (:NEW.empno, :NEW.ename, :NEW.salary, dept_var.deptno); END IF; END; /
リモート表は、オブジェクト表のように直接アクセスできませんが、オブジェクト・ビューでは、あたかもオブジェクト表であるかのように、リモート表にアクセスできます。
ワシントンD.C.およびシカゴに支店を持つ会社について考えてみます。各支店に、従業員表があります。ワシントンの本社には、すべての部門のリストを持つ部門表があります。組織全体のビューを作成するには、個々のリモート表の上にビューを作成し、次に組織全体のビューを作成します。
このためには、次の手順を実行する必要があります。
listener.ora
のエントリ((ADDRESS=(PROTOCOL=tcp)
(HOST=stadv07.us.example.com)(PORT=1640))
など)を更新します。
tnsnames.ora
にエントリ(chicago=(DESCRIPTION= (ADDRESS=(PROTOCOL=ipc)(KEY=linux)) (CONNECT_DATA=(SERVICE_NAME=linux.regress.rdbms.dev.us.example.com)))
など)を追加します。
例6-9に示すようなCREATE
DATABASE
LINK
コードを入力します。
例6-9では、各従業員表のオブジェクト・ビューを作成してから、グローバル・ビューを作成しています。
例6-9 リモート表にアクセスするためのオブジェクト・ビューの作成
-- Requires Ex. 6-2, Ex. 6-4, and Ex. 6-6 -- Example requires DB links, such as these, modify for your use and uncomment -- CREATE DATABASE LINK chicago CONNECT TO hr IDENTIFIED BY hr USING 'inst1'; -- CREATE DATABASE LINK washington CONNECT TO hr IDENTIFIED BY hr USING 'inst1'; CREATE VIEW emp_washington_view (eno, ename, salary, job) AS SELECT e.empno, e.empname, e.salary, e.job FROM emp@washington e; CREATE VIEW emp_chicago_view (eno, ename, salary, job) AS SELECT e.empno, e.empname, e.salary, e.job FROM emp@chicago e; CREATE VIEW orgnzn_view OF dept_t WITH OBJECT IDENTIFIER (deptno) AS SELECT d.deptno, d.deptname, address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr, CAST( MULTISET ( SELECT e.eno, e.ename, e.salary, e.job FROM emp_washington_view e) AS employee_list_t) AS emp_list FROM dept d WHERE d.deptcity = 'Washington' UNION ALL SELECT d.deptno, d.deptname, address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip) AS deptaddr, CAST( MULTISET ( SELECT e.eno, e.ename, e.salary, e.job FROM emp_chicago_view e) AS employee_list_t) AS emp_list FROM dept d WHERE d.deptcity = 'Chicago';
このビューは、各部門のすべての従業員のリストを持ちます。従業員は複数の部門に所属できないため、UNION
ALL
句が使用されています。
オブジェクト・ビューには、MAKE_REF
演算子を使用して、循環参照を定義できます。つまり、view_A
がview_B
を参照して、view_Bがview_A
を参照することもできます。これにより、リレーショナル・データで構成されるグラフのように複雑な構造を、オブジェクト・ビューが合成できるようになります。
たとえば、部門および従業員の例の場合、部門オブジェクトに従業員のリストが含まれています。領域を節約するために、部門オブジェクト内のすべての従業員を具体化せずに、従業員オブジェクトの参照を、部門オブジェクト内部に入れてみます。従業員オブジェクトへの参照を構成(確保)し、後でドット表記法を使用してこの参照に従い、従業員情報を抽出できます。
従業員オブジェクトはすでに従業員の所属部門への参照を持っているため、このモデルでのオブジェクト・ビューには、部門ビューと従業員ビューの間の循環参照が含まれます。
オブジェクト・ビュー間の循環参照は、次の2通りの方法で作成できます。
2つ目のビューを作成した後、最初のビューを作成する
ビューBへの参照を持たないビューAを作成します。
ビューAへの参照を含むビューBを作成します。
ビューAをビューBの参照を含む新しい定義で置換します。
「方法1: 2つ目のビューを作成した後、最初のビューを再作成する」の例を参照してください。
FORCE
キーワードを使用して最初のビューを作成する
FORCE
キーワードを使用して、ビューBへの参照を持つビューAを作成します。
ビューAの参照を持つビューBを作成します。ビューAを使用すると、妥当性チェックが行われ、再コンパイルされます。
「方法2: FORCEキーワードを使用して最初のビューを作成する」の例を参照してください。
方法2の方が、手順が簡単ですが、ビューの作成時に、FORCE
キーワードによりエラーが隠される可能性があります。ビュー作成中にエラーが発生したかどうかを確認するには、USER_ERRORS
カタログ・ビューを問い合せる必要があります。ビュー作成文の中にエラーがないことが保証されている場合にのみ、この方法を使用してください。
また、使用時にエラーによってビューが再コンパイルできない場合は、ALTER
VIEW
COMPILE
コマンドを使用し、ビューを手動で再コンパイルする必要があります。
循環ビュー参照の作成では、いずれの方法を使用する場合も、あらかじめ次に説明する設定を実行してください。
まず、リレーショナル表および対応付けられたオブジェクト型を設定する必要があります。表にオブジェクトが入っていても、この表はオブジェクト表ではありません。データ・オブジェクトにアクセスするために、後でオブジェクト・ビューを作成します。
emp
表には、従業員情報が入っています。
例6-10 循環参照を示すemp表の作成
CREATE TABLE emp ( empno NUMBER PRIMARY KEY, empname VARCHAR2(20), salary NUMBER, deptno NUMBER ); -- first create a dummy, that is, incomplete, department type, so emp_t type -- created later will succeed CREATE TYPE dept_t; / -- Create the employee type with a reference to the department,dept_t
: CREATE TYPE emp_t AS OBJECT ( eno NUMBER, ename VARCHAR2(20), salary NUMBER, deptref REF dept_t ); / -- Represent the list of references to employees as a nested table: CREATE TYPE employee_list_ref_t AS TABLE OF REF emp_t; / -- Create the department table as a relational table CREATE TABLE dept ( deptno NUMBER PRIMARY KEY, deptname VARCHAR2(20), deptstreet VARCHAR2(20), deptcity VARCHAR2(10), deptstate CHAR(2), deptzip VARCHAR2(10) ); -- Create object types that map to columns from the relational tables: CREATE TYPE address_t AS OBJECT ( street VARCHAR2(20), city VARCHAR2(10), state CHAR(2), zip VARCHAR2(10)); / -- Fill in the definition fordept_t
, the incomplete type you previously created: CREATE OR REPLACE TYPE dept_t AS OBJECT ( dno NUMBER, dname VARCHAR2(20), deptaddr address_t, empreflist employee_list_ref_t); /
例6-10に示すように、emp
表を作成してから、ダミーの部門型dept_t
を作成する必要があります(これにより、作成したemp_t
型が正常に機能できるようになります)。その後、dept_t
への参照を持つemp_t
を作成します。ネストした表employee_list_ref_t
として従業員への参照のリストを作成し、部門表dept
を作成します。次に、リレーショナル表にマップする列を持つオブジェクト型address_t
を作成し、最後に不完全なdept_t
の定義に埋め込みます。
使用できるデータ例を次に示します。
insert into emp values(1,'John','900',100); insert into emp values(2,'james','1000',100); insert into emp values(3,'jack',2000,200);
前の項で基礎となるリレーショナル表が完成したので、今度はこのリレーショナル表にオブジェクト・ビューを作成します。
方法1: 2つ目のビューを作成した後、最初のビューを再作成する
まず、deptref
列にNULLを持つ従業員ビューを作成します。後で、その列を参照に変えることができます。
次に、従業員オブジェクトへの参照を含む部門ビューを作成します。これにより、従業員オブジェクト全体を含めるのではなく、従業員オブジェクトへの参照のリストを作成します。
次に、部門ビューへの参照を持つ従業員ビューを再作成します。
例6-11 循環参照を持つオブジェクト・ビューの作成、方法1
-- Requires Ex. 6-10 CREATE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno) AS SELECT e.empno, e.empname, e.salary, NULL FROM emp e; -- create department view, including references to the employee objects CREATE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER(dno) AS SELECT d.deptno, d.deptname, address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip), CAST( MULTISET ( SELECT MAKE_REF(emp_view, e.empno) FROM emp e WHERE e.deptno = d.deptno) AS employee_list_ref_t) FROM dept d; CREATE OR REPLACE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno) AS SELECT e.empno, e.empname, e.salary, MAKE_REF(dept_view, e.deptno) FROM emp e;
これでビューが作成されました。
方法2: FORCEキーワードを使用して最初のビューを作成する
ビューを作成する文に構文エラーがないという確信があれば、FORCE
キーワードを使用して、他のビューを存在させずに、最初のビューを強制的に作成できます。
まず、この時点で存在しない部門ビューへの参照を含む従業員ビューを作成します。部門ビューが適切に作成されるまで、このビューの問合せは実行できません。
次に、従業員オブジェクトへの参照を含む部門ビューを作成します。emp_view
がすでに存在するため、ここでFORCE
キーワードを使用する必要はありません。これにより、部門ビューの問合せを実行し、ネストした表empreflist
からの従業員参照を解除することで従業員オブジェクトを取得できます。
例6-12 FORCEを持つビューの作成、方法2
-- Requires Ex. 6-10 -- create employee view CREATE OR REPLACE FORCE VIEW emp_view OF emp_t WITH OBJECT IDENTIFIER(eno) AS SELECT e.empno, e.empname, e.salary, MAKE_REF(dept_view, e.deptno) FROM emp e; -- create a department view that includes references to the employee objects CREATE OR REPLACE VIEW dept_view OF dept_t WITH OBJECT IDENTIFIER(dno) AS SELECT d.deptno, d.deptname, address_t(d.deptstreet,d.deptcity,d.deptstate,d.deptzip), CAST( MULTISET ( SELECT MAKE_REF(emp_view, e.empno) FROM emp e WHERE e.deptno = d.deptno) AS employee_list_ref_t) FROM dept d; -- Querying with DEREF method SELECT DEREF(e.COLUMN_VALUE) FROM TABLE( SELECT e.empreflist FROM dept_view e WHERE e.dno = 100) e;
COLUMN_VALUE
は、スカラーのネストした表の中のスカラー値を表す特別な名前です。この場合、COLUMN_VALUE
はネストした表empreflist
の中にある従業員オブジェクトの参照を示しています。
名前がJohn
で始まるすべての従業員の従業員番号のみにアクセスすることも可能です。
例6-13 COLUMN_VALUEを使用した問合せ
-- Requires Ex. 6-10 and 6-12 SELECT e.COLUMN_VALUE.eno FROM TABLE(SELECT e.empreflist FROM dept_view e WHERE e.dno = 100) e WHERE e.COLUMN_VALUE.ename like 'John%';
表形式で出力するには、部門表をネストした表の項目と結合し、参照のリストのネストを解除します。
例6-14 COLUMN_VALUEを使用した問合せ、参照のネスト解除
-- Requires Ex. 6-10 and 6-12SELECT d.dno, e.COLUMN_VALUE.eno, e.COLUMN_VALUE.ename FROM dept_view d, TABLE(d.empreflist) e WHERE e.COLUMN_VALUE.ename like 'John%' AND d.dno = 100;
最後に、dept_view
のかわりにemp_view
を使用するように、前述の問合せを書きなおし、ビュー間をナビゲートする方法を紹介します。
オブジェクト・ビュー階層は、オブジェクト・ビューの集合で、型階層内の様々な型が、それぞれのオブジェクト・ビューの基になっています。ビュー階層内のサブビューは、型階層内のサブタイプがスーパータイプの下に作成される場合と同じ方法で、スーパービューの下に作成されます。
ビュー階層内のそれぞれのオブジェクト・ビューは、1つの型のオブジェクトと一緒に移入されますが、任意のビューについての問合せでは、そのサブビューも暗黙的に扱います。このように、オブジェクト・ビュー階層により、一定のレベルまたはそれ以上のレベルに特化されたオブジェクトの多相集合を返す問合せを、簡単に組み立てられます。
person_typ
をルートとする、次のような型階層について考えてみます。
オブジェクト・ビューをそれぞれの型に基づいて作成し、この型階層に基づいてオブジェクト・ビュー階層を作成しておくと、目的の特化レベルと対応するオブジェクト・ビューの問合せができます。たとえば、student_typ
のビューについて問い合せ、学生(定時制の学生を含む)のみ入っている結果セットを取得できます。
型階層内のいずれの型も、オブジェクト・ビュー階層のルート・ビューの基として使用できます。つまり、オブジェクト・ビュー階層をルート型から組み立てる必要はありません。また、オブジェクト・ビュー階層を型階層の各リーフまで拡張したり、すべてのブランチを範囲に入れる必要もありません。ただし、下位に介在するサブタイプは省略できません。いずれのサブビューも、直系スーパービューの型の直系サブタイプに基づく必要があります。
型が兄弟関係にあるサブタイプを2つ以上持てるように、オブジェクト・ビューも兄弟関係にあるサブビューを2つ以上持てます。ただし、任意の型に基づくサブビューが関与できるのは、1つのオブジェクト・ビュー階層のみです。2つの異なるオブジェクト・ビュー階層に、同じサブタイプに基づく1つのサブビューが存在することはありません。
サブビューはスーパービューからオブジェクト識別子(OID)を継承します。任意のサブビューに、OIDを明示的に指定することは許可されません。
ルート・ビューでは、WITH OBJECT ID
句を使用して、オブジェクト識別子を明示的に指定できます。OIDがシステムによって生成される場合、またはルート・ビューに句を指定しない場合、サブビューを作成できるのは、同様にシステム生成のOIDを使用する表またはビューがルート・ビューの基になっている場合のみです。
ビューの基礎となる問合せにより、ビューが更新可能かどうかが決まります。ビューの問合せに、結合、集合演算子、集計ファンクション、GROUP
BY
句、DISTINCT
句、疑似列または式を何も入れないというのが、ビューを更新可能にするための条件です。サブビューについても同じ条件が適用されます。
ビューが更新可能でなくても、適切なDML処理を実行するためのINSTEAD
OF
トリガーが定義できます。サブビューはINSTEAD
OF
トリガーを継承しない点に注意してください。
ビュー階層内のすべてのビューは、同じスキーマに所属する必要があります。
注意: インスタンス化不可の型のビューを作成できます。インスタンス化不可の型は、インスタンスを持つことはできないので、このような型のオブジェクト・ビューを作成しても意味がありません。ただし、インスタンス化不可の型は、インスタンス化可能なサブタイプを持つことができます。インスタンス化不可の型のオブジェクト・ビューを作成できるため、インスタンス化不可の型が含まれている型階層をオブジェクト・ビュー階層の基にすることができます。 |
オブジェクト・ビュー階層は、ルート・ビューの下にサブビューを作成して、構築します。このためには、例6-17のようにCREATE
VIEW
文でUNDER
キーワードを使用します。
基礎となる様々な記憶域モデルが、同じオブジェクト・ビュー階層の基になることもあります。つまり、基礎となる表の様々なレイアウトや設計により、同じオブジェクト・ビュー階層が作成される可能性があるということです。基礎となる記憶域モデルの設計は、オブジェクト・ビュー階層のパフォーマンスや更新可能性に影響を与えます。
この項では、考えられる3種類の記憶域モデルを示します。最初のフラット・モデルの場合、オブジェクト・ビュー階層内のすべてのビューの基は、同じ表です。2番目の水平モデルの場合、それぞれのビューは、それぞれ別の表と1対1で対応します。3番目の垂直モデルの場合は、結合を使用してビューが構成されます。
これらの記憶域モデルを実行するには、まず例6-16に示すような型を作成します。
例6-16 記憶域モデル例に使用する型の作成
CREATE TYPE person_typ AS OBJECT ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL;/ CREATE TYPE student_typ UNDER person_typ ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL;/ CREATE TYPE employee_typ UNDER person_typ ( empid NUMBER, mgr VARCHAR2(30));/
この項の内容は次のとおりです。
フラット・モデルの場合、オブジェクト・ビュー階層内のすべてのビューの基となるのは、同じ表です。次に例に示すAllPersons
という1つの表には、person_typ
、student_typ
およびemployee_typ
のすべての属性の列が格納されます。
それぞれの行の型は、typeid
列により識別されます。これらの有効な値は、例6-16で作成した型(1 = person_typ
、2 = student_typ、
3 = employee_typ
)です。
例6-17では、表AllPersons
を作成してから、オブジェクト・ビュー階層を構成するビューを作成します。
例6-17 オブジェクト・ビュー階層の作成
-- Requires Ex. 6-16 CREATE TABLE AllPersons ( typeid NUMBER(1), ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100), deptid NUMBER, major VARCHAR2(30), empid NUMBER, mgr VARCHAR2(30)); CREATE VIEW Person_v OF person_typ WITH OBJECT OID(ssn) AS SELECT ssn, name, address FROM AllPersons WHERE typeid = 1; CREATE VIEW Student_v OF student_typ UNDER Person_v AS SELECT ssn, name, address, deptid, major FROM AllPersons WHERE typeid = 2; CREATE VIEW Employee_v OF employee_typ UNDER Person_v AS SELECT ssn, name, address, empid, mgr FROM AllPersons WHERE typeid = 3;
単純である、という点がフラット・モデルの利点です。また、フラット・モデルが、索引や制約への対応に支障をきたす原因になることはありません。このモデルのデメリットは、次のとおりです。
1つの表に格納できる列は1000以下のため、フラット・モデルでは、オブジェクト・ビュー階層に格納できる列の合計数が、1000列に制限されます。
表の各列には、オブジェクト・ビューの型に属さないすべての属性のかわりにNULLが入ってしまいます。このようにNULLが後続しない状態は、パフォーマンスを低下させる可能性があります。
水平モデルの場合、それぞれのビューまたはサブビューの基になるのは、異なる表です。例に示す表はリレーショナル表ですが、これらの表は、列の代入性が無効になるオブジェクト表になる場合もあります。
例6-18では、表を作成してから、これらの表に基づくビューを作成します。
例6-18 表の水平モデルの作成
-- Requires Ex. 6-16 and Ex. 6-17 CREATE TABLE only_persons ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)); CREATE TABLE only_students ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100), deptid NUMBER, major VARCHAR2(30)); CREATE TABLE only_employees ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100), empid NUMBER, mgr VARCHAR2(30)); CREATE OR REPLACE VIEW Person_v OF person_typ WITH OBJECT OID(ssn) AS SELECT * FROM only_persons; CREATE OR REPLACE VIEW Student_v OF student_typ UNDER Person_v AS SELECT * FROM only_students; CREATE OR REPlACE VIEW Employee_v OF employee_typ UNDER Person_v AS SELECT * FROM only_employees;
水平モデルを使用すると、非常に効率的なのは、次のような構成の問合せです。
例6-19 ビューの水平モデルの問合せ
-- Requires Ex. 6-16 and Ex. 6-17 -- add the following data insert into only_persons values(1234,'John','abc'); insert into only_students values(1111,'James','abc',100,'CS'); insert into only_employees values(2222,'jack','abc',400,'Juliet'); SELECT VALUE(p) FROM Person_v p WHERE VALUE(p) IS OF (ONLY student_typ); OUTPUT: VALUE(P)(SSN, NAME, ADDRESS) -------------------------------------------------------------------------------- STUDENT_TYP(1111, 'James', 'abc', 100, 'CS')
このような問合せでは、特定の型のオブジェクトをすべて取得するために、1つの物理表にアクセスするのみですみます。このモデルのデメリットは、SELECT * FROM
view
のような問合せでは、基礎となるすべての表に対してUNION
を実行し、指定されたビューの列に対してのみ行を投影する必要があることです。(「階層内のビューの問合せ」を参照してください。)また、属性(および一意制約)についての索引は複数の表をまたがる必要がありますが、現在この機能はサポートされていません。
垂直モデルの場合、階層内のそれぞれのビューと対応する物理表が存在しますが、物理表に格納されるのは、対応するサブタイプに固有の属性のみです。
例6-20では、表を作成してから、対応するビューを作成します。
例6-20 表およびビューの垂直モデルの作成
CREATE TABLE all_personattrs ( typeid NUMBER, ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)); CREATE TABLE all_studentattrs ( ssn NUMBER, deptid NUMBER, major VARCHAR2(30)); CREATE TABLE all_employeeattrs ( ssn NUMBER, empid NUMBER, mgr VARCHAR2(30)); CREATE OR REPLACE VIEW Person_v OF person_typ WITH OBJECT OID(ssn) AS SELECT ssn, name, address FROM all_personattrs WHERE typeid = 1; CREATE OR REPLACE VIEW Student_v OF student_typ UNDER Person_v AS SELECT x.ssn, x.name, x.address, y.deptid, y.major FROM all_personattrs x, all_studentattrs y WHERE x.typeid = 2 AND x.ssn = y.ssn; CREATE OR REPLACE VIEW Employee_v OF employee_typ UNDER Person_v AS SELECT x.ssn, x.name, x.address, y.empid, y.mgr FROM all_personattrs x, all_employeeattrs y WHERE x.typeid = 3 AND x.ssn = y.ssn;
垂直モデルでは、SELECT * FROM
root_view
のような問合せが効率的に処理され、また、個々の属性に索引を付けたり、属性に一意制約を付けることができます。ただし、型のインスタンスを再作成するには、それぞれのレベルについて、階層のルートから型を削除するオブジェクト識別子(OID)の結合を実行する必要があります。
オブジェクト・ビュー階層内の任意のビューまたはサブビューに対し、問合せを実行できます。問合せにより戻されるのは、問い合せたビューの宣言された型の行と、その型のサブタイプの行です。たとえば、person_typ
型階層が基になっているオブジェクト・ビュー階層では、person_typ
のビューを問い合せて、学生や従業員を含む個人全員が格納されている結果セットを取得したり、student_typ
のビューを問い合せて、学生(定時制の学生を含む)のみ格納されている結果セットを取得できます。
問合せのSELECT
構文のリストには、オブジェクト・インスタンスを戻すREF()
やVALUE()
のようなファンクションを含めるか、またはperson_typ
のname
やssn
属性のようなビューの宣言された型のオブジェクト属性を指定できます。
オブジェクト・インスタンスを戻すためにファンクションを指定すると、問合せにより多相結果セットが戻されます。つまり、ビューの宣言された型のインスタンスと、その型のサブタイプのインスタンスのどちらも戻されます。
たとえば、次の問合せでは、あらゆる型の個人、従業員および学生のインスタンスのみでなく、これらのインスタンスREF
も戻されます。
例6-21 REFと値での問合せ
-- Requires Ex. 6-20 insert into all_personattrs values(1,1111,'John','abc'); insert into all_personattrs values(2,2222,'Jack','def'); insert into all_personattrs values(3,3333,'James','ghi'); insert into all_studentattrs values(2222,100,'CS'); insert into all_employeeattrs values(3333,444,'Julia'); SELECT REF(p), VALUE(p) FROM Person_v p; OUTPUT: REF(P) -------------------------------------------------------------------------------- VALUE(P)(SSN, NAME, ADDRESS) -------------------------------------------------------------------------------- 00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000 090600812A00078401FE0000000B03C20C0C00000000000000000000000000000000000000 PERSON_TYP(1111, 'John', 'abc') 00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000 090600812A00078401FE0000000B03C2222200000000000000000000000000000000000000 EMPLOYEE_TYP(3333, 'James', 'ghi', 444, 'Julia') 00004A038A00465A6E6E779EC1F25FE040578CE70A447E0000001426010001000100290000000000 REF(P) -------------------------------------------------------------------------------- VALUE(P)(SSN, NAME, ADDRESS) -------------------------------------------------------------------------------- 090600812A00078401FE0000000B03C2171700000000000000000000000000000000000000 STUDENT_TYP(2222, 'Jack', 'def', 100, 'CS')
ビューの宣言された型の個々の属性をSELECT
構文のリストに指定した場合、またはSELECT
*
を実行した場合も、ビューの宣言された型およびこの型のサブタイプの行が戻されます。ただし、これらの行が投影される先は、ビューの宣言された型の属性の列で、使用されるのは、これらの列のみです。つまり、サブタイプを表現する対象は、ビューの宣言された型からサブタイプが継承した属性、およびサブタイプがビューの宣言された型と共有する属性のみです。
たとえば、次の問合せでは、個人全員の行およびあらゆる型の従業員および学生の行が戻されますが、結果に使用されるのは、person_typ
の属性(name
、ssn
およびaddress
)の列のみです。student_typ
のdeptid
属性などサブタイプに追加された属性の行は、何も表示されません。
SELECT * FROM Person_v;
結果からサブビューを除外するには、ONLY
キーワードを使用します。ONLY
キーワードにより、選択対象が、問合せ対象のビューの宣言された型に限定されます。
SELECT VALUE(p) FROM ONLY(Person_v) p;
通常、サブビューを持つビューについての問合せで要求されるのは、参照対象のビューについてのSELECT
権限のみで、サブビューについての明示的な権限は要求されません。次に示す問合せでは、Person_v
についてのSELECT
権限のみ要求され、このビューのサブビューについての権限は要求されません。
SELECT * FROM Person_v;
ただし、サブタイプの属性として追加されていても、ルート型では使用しない属性を選択する問合せの場合は、サブビューについてのSELECT
権限も要求されます。このようなサブタイプ属性には、別のアクセス権限を適度に必要とする機密情報が格納されている可能性があります。
次に示す問合せでは、オブジェクト・インスタンスが選択され、その結果、サブタイプのすべての属性が取り出されるため、Person_v
、Student_v
、Employee_v
(およびPerson_v
のサブビュー)についてのSELECT
権限が要求されます。
SELECT VALUE(p) FROM Person_v p;
ビュー階層全体についてのSELECT
権限を付与する処理を簡素化するには、HIERARCHY
オプションが使用できます。ビューについてのSELECT
権限をユーザーに付与するときに、HIERARCHY
オプションを指定すると、現在および将来存在するビューのすべてのサブビューについてのSELECT
権限も暗黙的に付与されます。次に例を示します。
GRANT SELECT ON Person_v TO user WITH HIERARCHY OPTION;
サブビューに属する行を除外する問合せには、すべてのサブビューについてのSELECT
権限も要求されます。その理由は、インスタンスの最も狭い意味での型にのみ属している行の情報は、機密情報の可能性があり、すべての行をサブビューから除外する問合せ(次に示すような問合せ)の場合は、サブビューについてのSELECT
権限が要求されるためです。
SELECT * FROM ONLY(Person_v);