PLSQL入门与精通(第73章:视图的更新)

本次我们讲解通过视图来更新数据的相关内容。

视图本来是一个查询询的。假如通过视图可以直接对查询对象的数据进行的话,
那么查询的对象和更新的对象都在一个视图里边的话,构建应用程序就变得简单了。
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触发器”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值