天天看點

允許進行DML操作的視圖條件

視圖可以屏蔽某些基表的資訊,或是join多個基表組成一個複雜查詢,視圖本身也是可以進行DML操作,但受一些條件的限制。

首先我們看下官方文檔對視圖進行DML操作的要求說明:

The following notes apply to updatable views:

An updatable view is one you can use to insert, update, or delete base table rows. You can create a view to be inherently updatable, or you can create an <code>INSTEAD OF</code> trigger on any

view to make it updatable.

這裡說明了兩種可updateable(包括增删改基表)視圖的方法:一是繼承基表的視圖,二是使用INSTEAD OF的觸發器來實作任意視圖的updatable。

To learn whether and in what ways the columns of an inherently updatable view can be modified, query the <code>USER_UPDATABLE_COLUMNS</code> data dictionary view. The information displayed by

this view is meaningful only for inherently updatable views. 

USER_UPDATABLE_COLUMNS資料字典視圖可以找到視圖的哪些字段可以進行增加、更新和删除。

For a view to be inherently updatable, the following conditions must be met:

對于這種updatable繼承的視圖,需要滿足以下條件:

1. Each column in the view must map to a column of a single table. For example, if a view column maps to the output of a <code>TABLE</code> clause (an unnested collection), then the view is

not inherently updatable.

2. The view must not contain any of the following constructs:

    A set operator

    A <code>DISTINCT</code> operator

    An aggregate or analytic function

    A <code>GROUP</code> <code>BY</code>, <code>ORDER</code> <code>BY</code>, <code>MODEL</code>, <code>CONNECT</code> <code>BY</code>, or <code>START</code> <code>WITH</code> clause

    A collection expression in a <code>SELECT</code> list

    A subquery in a <code>SELECT</code> list

    A subquery designated <code>WITH READ ONLY</code>

    Joins, with some exceptions, as documented in 

3.

In addition, if an inherently updatable view contains pseudocolumns or expressions, then you cannot update base table rows with an <code>UPDATE</code> statement

that refers to any of these pseudocolumns or expressions.

4. If you want a join view to be updatable, then all of the following conditions must be true:

對于一個join視圖,如果需要可updatable,那麼就需要滿足如下條件:

(1) The DML statement must affect only one table underlying the join.

DML必須僅影響一個join連接配接的表。

(2) For an <code>INSERT</code> statement, the view must not be created <code>WITH</code> <code>CHECK</code> <code>OPTION</code>,

and all columns into which values are inserted must come from a key-preserved table. A key-preserved table is one for which every primary key or

unique key value in the base table is also unique in the join view.

INSERT語句,不能使用WITH CHECK OPTION,并且所有待插入的列都來自于key-preserved表。

key-preserved表是指基表中每個主鍵或唯一鍵也必須是在join視圖中唯一。

(3) For an <code>UPDATE</code> statement, the view must not be created <code>WITH</code> <code>CHECK</code> <code>OPTION</code>,

and all columns updated must be extracted from a key-preserved table.

UPDATE語句,視圖不能使用WITH CHECK OPTION建立,同樣更新字段也必須來自于key-preserved表。

5. For a <code>DELETE</code> statement, if the join results in more than one key-preserved table, then Oracle

Database deletes from the first table named in the <code>FROM </code>clause, whether or not the view was created <code>WITH</code> <code>CHECK</code> <code>OPTION</code>.

DELETE語句,如果join結果有多個key-preserved表,Oracle隻會删除FROM子句中第一個表的記錄,不管視圖是否使用WITH CHECK OPTION。

下面通過一系列實驗來說明。

建立測試表:

create table dept(deptid int primary key, deptname varchar2(20));

create table employee(empid int primary key, empname varchar2(20), deptid int);

建立測試資料:

insert into dept values(1,‘dept1‘);

insert into dept values(2,‘dept2‘);

insert into dept values(3,‘dept3‘);

insert into employee values(1,‘emp1‘,1);

insert into employee values(2,‘emp2‘,1);

insert into employee values(3,‘emp3‘,2);

建立視圖:

create view testv

as select d.deptid deptid, deptname, empid, empname, e.deptid edeptid

from dept d join employee e

on d.deptid = e.deptid;

SQL&gt; select * from testv;

 DEPTID   DEPTNAME               EMPID  EMPNAME            EDEPTID

---------- -------------------- ---------- -------------------- ----------

          1   dept1                         1           emp1                    1

          1   dept1                         2           emp2                    1

          2   dept2                         3           emp3                    2

僅employee表是key-preserved表。

測試1:對key-preserved表字段進行增加、更新的操作。

update testv set empname=‘empx‘ where edeptid=1;

update testv set empname=‘empx‘ where empid=1;

update testv set empname=‘empx‘ where deptid=1;

insert into testv(empid,empname,edeptid) values(4,‘emp4‘,2);

以上SQL可以執行,因為修改或添加的字段都是employee的,即key-preserved表。

測試2:驗證上述“DELETE語句,如果join結果有多個key-preserved表,Oracle隻會删除FROM子句中第一個表的記錄,不管視圖是否使用WITH CHECK OPTION”。

from employee e join dept d

on d.deptid = e.deptid

WITH CHECK OPTION;

select * from testv;          

  DEPTID  DEPTNAME           EMPID      EMPNAME           EDEPTID

         1    dept1                         1          emp1                          1

         1    dept1                         2          emp2                          1

         2    dept2                         3          emp3                          2

delete from testv where deptid = 1;

2 rows deleted.

select * from dept;

   DEPTID  DEPTNAME

---------- --------------------

         1      dept1

         2      dept2

         3      dept3

select * from employee;

  EMPID   EMPNAME            DEPTID

---------- -------------------- ----------

         3     emp3                          2

delete from testv where empid = 1;

1 row deleted.

select * from testv;

  DEPTID   DEPTNAME           EMPID    EMPNAME            EDEPTID

         1      dept1                         2       emp2                          1

         2      dept2                         3       emp3                          2

  DEPTID   DEPTNAME

   EMPID   EMPNAME            DEPTID

         2      emp2                          1

         3      emp3                          2

測試3:對于INSERT和UPDATE語句,不能使用WITH CHECK OPTION建立視圖。

create view test1v  

as select t1id ,t1v,t2id,t2v 

from test1 join test2 

on test1.t1id=test2.t2id 

with check option;

insert into test1v(t1id,t1v) values(4,‘t4‘);

                   *

ERROR at line 1:

ORA-01733: virtual column not allowed here

update test1v set t1id=4 where t1id=1;

                  *

測試4:非key-preserved表字段不能更新或插入。

update testv set deptname=‘deptx‘ where deptid=1

update testv set deptname=‘deptx‘ where empid=1

insert into testv(deptid,deptname) values(4,‘dept4‘)

ORA-01779: cannot modify a column which maps to a non key-preserved table

測試5:檢視視圖中哪些字段可以增删改。

select * from USER_UPDATABLE_COLUMNS where table_name=‘TESTV‘;

OWNER TABLE_NAME

COLUMN_NAME UPD INS DEL

-------------------------------------------------------------------------------------------

DCSOPEN TESTV

DEPTID NO  NO  NO

DEPTNAME NO  NO  NO

EMPID YES YES YES

EMPNAME YES YES YES

EDEPTID YES YES YES

If

you want a join view to be updatable, then all of the following conditions must be true: