本次我们讲解通过视图来更新数据的相关内容。
视图本来是一个查询询的。假如通过视图可以直接对查询对象的数据进行的话,
那么查询的对象和更新的对象都在一个视图里边的话,构建应用程序就变得简单了。
Oracle就可以实现这个我们想要的功能。
通过视图更新数据,有的时候是可以更新的,有的时候不能更新数据。
通过视图更新数据是有前提条件的。如果不符合这个条件,原则上无法通过视图更新数据。
但是,即使在这种情况下,我们也可以通过“INSTEADOF触发”的触发器,通过视图进行数据更新,
这个是我们下一节要说明的内容。这次我们只是说明通过视图更新数据的一般原则。
首先大家都知道,视图是数据库对象的查询(SELECT)而定义的一个对象。
可以说是把SELECT文的结果伪装成表的一个虚拟表。
对视图进行查询(SELECT)的话,内部会转换成对实际表的查询。
对视图的更新(DML语句:INSERT,UPDATE,DELETE)也同样会在内部转换成对实际表的DML语句。
但是,对于复杂的SELECT语句为基础定义的视图,则无法转换成对实际表的DML语句,这时候会发生错误。
那么,对于怎样的视图,我们针对视图实施DML语句会出错呢?总结一下:
大致如下3点。
1.带有函数列视图的时候,无法更新该列
2.有外部按键约束的父表、子表结合的视图中,不能更新父表的列
3.在以汇集数据(SUM之类的)的SELECT语句为基础的视图中不能执行DML语句
下面分别进行说明。
1.带有函数列视图的时候,无法更新该列
如果视图中的某列没有显示原始的表数据,是经过加工过的列,这时候是则无法更新该列。
例如,有以下视图:。
CREATE OR REPLACE VIEW V_TEST1
AS
SELECT EMPNO, ENAME, LOWER (ENAME) AS LOW_NAME FROM EMP;
创建了视图。
查询一下这个视图:
SELECT * FROM V_TEST1;
EMPNO ENAME LOW_NAME
7369 SMITH smith
7499 ALLEN allen
7521 WARD ward
7566 JONES jones
7654 MARTIN martin
7698 BLAKE blake
7782 CLARK clark
7788 SCOTT scott
(以下略)
此视图的第二列显示EMP表的ENAME列,它是没有加工过的列,我们可以更新这个视图的列。
让我们尝试一下:
UPDATE V_TEST1 SET ENAME = ‘SMITH2’ WHERE EMPNO = 7369;
一行已更新。
如我们所所料,视图的列可以被更新,但是实际上更新的是EMP表的数据。
SELECT ENAME FROM EMP WHERE EMPNO = 7369;
ENAME
SMITH2
但是,该视图的第3列(LOW NAME列)不是直接显示EMP表的ENAME列,
是带有函数的列,它是通过LOWER函数转换成小写字父来显示。
对于这样的列的视图,DML是无法更新该视图的列的,更新会发生错误,例如:
UPDATE V_TEST1 SET LOW_NAME = ‘SMITH3’ WHERE EMPNO = 7369;
行1发生错误。:
ORA-01733:这里不能使用虚拟列。
这是无法通过视图更新数据的第一种情况,接下来介绍第二种情况。
2.有外部按键约束的父表、子表结合的视图中,不能更新父表的列
解释如下:一个视图是结合了父表和子表的视图,父子表有外键相互约束,父子表数据是1对多的,
也就是说父表的一行数据在视图中是多行数据,不是一对一,子表数据是一行显示一行的。
对于这样的视图,是不能通过视图用DML语句操作父表的这个列的。
例如,创建一个视图,它是结合了EMP表(子)和DEPT表(父)的视图。
CREATE OR REPLACE VIEW V_QIN_ZI
AS
SELECT E.EMPNO, E.ENAME, D.DNAME
FROM EMP E , DEPT D
WHERE E.DEPTNO = D.DEPTNO
创建了视图。
我来查询一下这个视图:
SELECT * FROM V_QIN_ZI;
EMPNO ENAME DNAME
7782 CLARK ACCOUNTING
7839 KING ACCOUNTING
7934 MILLER ACCOUNTING
7566 JONES RESEARCH
此视图的第一列和第二列是EMP表(子)列,可以通过视图来更新。
UPDATE V_QIN_ZI
SET ENAME = ‘king’
WHERE EMPNO = 7839;
一行已更新。
但是第3列是DEPT表(父)列,则不能通过视图更新该列,例如:
UPDATE V_QIN_ZI
SET DNAME = UPPER (DNAME)
WHERE EMPNO = 7389
/
行2发生错误。:
ORA-01779:无法更改映射到未保存按键表的列
这样会出错。
第3列的部门名称(DNAME列)的ACCOUNTIGN值,在父表的DEPT表中仅存在1行的数据,
但在与子表结合的视图中显示成了多行数据。无法和原表一一对应起来,
所以这样的父表多的列是不能通过视图来更新的。
接下来介绍无法通过视图更新数据第三种情况。
3.在以汇集数据(SUM之类的)的SELECT语句为基础的视图中不能执行DML语句
这意味着,对于表中多行集中在视图的一行中的视图,DML是不可能的。
例如,针对员工表,显示各部门的工资合计,创建以下视图
CREATE OR REPLACE VIEW V_GSAL
AS
SELECT DEPTNO, SUM (SAL) AS GSAL
FROM EMP
GROUP BY DEPTNO;
创建了视图。
查询此视图。
SELECT * FROM V_GSAL;
DEPTNO GSAL
30 9400
20 10875
10 9029
这个结果就是是每个部门的合计工资。这里,我们试着将DEPTNO=10行的GSAL列更新为合计值的2倍。
UPDATE V_GSAL
SET GSAL = GSAL * 2
WHERE DEPTNO = 10;
行1发生错误。:
ORA-01732:此视图中数据操作无效
这样会出错。
这是因为这个视图的一行对应EMP表的多行数据,视图无法和元实体表一一对应,
所以这种情况下也不能郭不能进行更新操作。
这也是可以理解的。
例如,在上述3.的例子中,我们想通过视图直接更新某列,
譬如我们想通过视图,将DEPTNO=10行的工资合计列(GSAL列)更新为2倍,可能么?
可能,这就是下次介绍的内容,使用“INSTEADOF触发”就可以了。
这是对视图的触发器相关的内容。。
本次到此为止。下次介绍“INSTEADOF触发器”。