《oracle马拉松》view篇

发布时间 2023-03-28 10:52:16作者: Fusio

视图的定义

视图(view),也称虚表, 不占用物理空间,这个也是相对概念,因为视图本身的定义语句还是要存储在数据字典里的。视图只有逻辑定义。每次使用的时候,只是重新执行SQL。
当通过视图修改数据时,实际上是在改变基表中的数据;相反地,基表数据的改变也会自动反映在由基表产生的视图中。由于逻辑上的原因,有些Oracle视图可以修改对应的基表,有些则不能(仅仅能查询)。
tips: 查询视图没有什么限制, 插入/更新/删除视图的操作会受到一定的限制; 所有针对视图的操作都会影响到视图的基表; 为了防止用户通过视图间接修改基表的数据, 可以将视图创建为只读视图(带上with read only选项)

创建视图

1 权限:

要在当前方案中创建视图, 用户必须具有create view系统权限; 要在其他方案中创建视图, 用户必须具有create any view系统权限. 视图的功能取决于视图拥有者的权限.

2 语法:

create [ or replace ] [ force ] view [schema.]view_name
					  [ (column1,column2,...) ]
					  as
					  select ...
					  [ with check option ]
					  [ constraint constraint_name ]
					  [ with read only ];

tips:
1 or replace: 如果存在同名的视图, 则使用新视图"替代"已有的视图
2 force: "强制"创建视图,不考虑基表是否存在,也不考虑是否具有使用基表的权限
3 column1,column2,...:视图的列名, 列名的个数必须与select查询中列的个数相同; 如果select查询包含函数或表达式, 则必须为其定义列名.此时, 既可以用column1, column2指定列名, 也可以在select查询中指定列名.
4 with check option: 指定对视图执行的dml操作必须满足“视图子查询”的条件即,对通过视图进行的增删改操作进行"检查",要求增删改操作的数据, 必须是select查询所能查询到的数据,否则不允许操作并返回错误提示. 默认情况下, 在增删改之前"并不会检查"这些行是否能被select查询检索到.
5 with read only:创建的视图只能用于查询数据, 而不能用于更改数据.
6 alter view 视图名 compile,当视图依赖的基表改变后,视图会“失效”。为了确保这种改变“不影响”视图和依赖于该视图的其他对象,应该使用 alter view 语句“明确的重新编译”该视图,为了重新编译其他模式中的视图,必须拥有alter any table系统权限。注意:当访问基表改变后的视图时,oracle会“自动重新编译”这些视图。
7 查看视图,使用数据字典视图

1 dba_views——DBA视图描述数据库中的所有视图
2 all_views——ALL视图描述用户“可访问的”视图
3 user_views——USER视图描述“用户拥有的”视图
4 dba_tab_columns——DBA视图描述数据库中的所有视图的列(或表的列)
5 all_tab_columns——ALL视图描述用户“可访问的”视图的列(或表的列)
6 user_tab_columns——USER视图描述“用户拥有的”视图的列(或表的列)

3.1 创建简单视图

简单视图定义:是指基于单个表建立的,不包含任何函数、表达式和分组数据的视图。

SQL> conn /as sysdba
Connected.
SQL> grant create view to scott;
SQL> conn scott/tiger
Connected.
SQL> create view vw_emp as select empno,ename,job,hiredate,deptno from emp;
SQL> desc vw_emp
 Name                                      Null?    Type
 ------------------------------- -------- ----------------------------
 EMPNO                                     NOT NULL NUMBER(4)
 ENAME                                              VARCHAR2(10)
 JOB                                                VARCHAR2(9)
 HIREDATE                                           DATE
 DEPTNO                                             NUMBER(2)

SQL> select * from vw_emp where deptno=10;
	 EMPNO ENAME      JOB       HIREDATE      DEPTNO
----------  ----------     ---------    ---------      
	  7782 CLARK      MANAGER    09-JUN-81          10
	  7839 KING       PRESIDENT   17-NOV-81         10
	  7934 MILLER     CLERK       23-JAN-82          10

对简单视图进行DML操作

SQL> insert into vw_emp values(1,'a','aa','05-JUN-88',10);
SQL> update vw_emp set ename='cc' where ename='KING';
SQL> delete vw_emp where ename='cc';
SQL> select * from vw_emp where deptno=10;
	 EMPNO ENAME      JOB       HIREDATE      DEPTNO
---------- ---------- --------- --------- ----------
	  7782 CLARK      MANAGER   09-JUN-81         10
	  7934 MILLER     CLERK     23-JAN-82         10
		 1 a          aa        05-JUN-88         10

基表也发生了相应的更改

SQL> select empno,ename,job,hiredate,deptno from emp where deptno=10;
 EMPNO ENAME      JOB       HIREDATE      DEPTNO
---------- ---------- --------- --------- ----------
  7782 CLARK      MANAGER   09-JUN-81         10
  7934 MILLER     CLERK     23-JAN-82         10
     1 a          aa        05-JUN-88         10

SQL> select object_name,object_type from user_objects;
OBJECT_NAME                    OBJECT_TYPE
------------------------------ -------------------
VW_EMP                         VIEW
SALGRADE                       TABLE
BONUS                          TABLE
PK_EMP                         INDEX
EMP                            TABLE
DEPT                           TABLE
PK_DEPT                        INDEX
7 rows selected.

创建只读视图with read only

SQL> create view vw_emp_readonly as select empno,ename,job,hiredate,deptno from emp with read only;
SQL> select * from vw_emp_readonly where deptno=10;
	 EMPNO ENAME      JOB       HIREDATE      DEPTNO
---------- ---------- --------- --------- ----------
	  7782 CLARK      MANAGER   09-JUN-81         10
	  7934 MILLER     CLERK     23-JAN-82         10
		 1 a          aa        05-JUN-88         10

只能查询,无法进行更改

SQL> delete vw_emp_readonly where empno=1;
delete vw_emp_readonly where empno=1
	   *
ERROR at line 1:
ORA-42399: cannot perform a DML operation on a read-only view

创建检查约束视图with check option

Sql>create view vw_emp_check as select empno,ename,job,hiredate,deptno from emp where deptno=10 with check option;
SQL> insert into vw_emp_check values('2','c','cc','02-JAN-55',10);
SQL> insert into vw_emp_check values('3','d','dd','02-JAN-65',20);
insert into vw_emp_check values('3','d','dd','02-JAN-65',20)
			*
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation

创建检查视图:对通过视图进行的增删改操作进行检查,要求增删改操作的数据必须是select查询所能查询到的数据

20号部门不在查询范围内,违反检查约束,所以无法插入;

SQL> delete vw_emp_check where empno=2;
1 row deleted.
--所删除的数据在查询范围内,不违反检查约束 

3.2 连接视图

3.2.1 连接视图定义:
是指基于多个表所创建的视图,即,定义视图的查询是一个连接查询。 主要目的是为了简化连接查询;

3.2.2 创建连接视图
示例1: 查询部门编号为10和30的部门及雇员信息

SQL> create view vw_dept_emp
  as select a.deptno,a.dname,a.loc,b.empno,b.ename,b.sal from dept a,emp b where a.deptno=b.deptno and a.deptno in(10,30);
View created.

3.2.3 连接视图上的DML操作

SQL> insert into vw_dept_emp values(10,'aaa','aaaa',22,'a',5000);
insert into vw_dept_emp values(10,'aaa','aaaa',22,'a',5000)
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table

在视图上进行的所有DML操作,最终都会在基表上完成;
select 视图没有什么限制,但insert/delete/update有一些限制;

3.2.4键值保存表

如果连接视图中的一个“基表的键”(主键、唯一键)在它的视图中仍然存在,并且“基表的键”仍然是“连接视图中的键”(主键、唯一键);即,某列在基表中是主键|唯一键,在视图中仍然是主键|唯一键,则称这个基表为“键值保存表”
一般地,由主外键关系的2个表组成的连接视图,外键表就是键值保存表,而主键表不是。

3.2.5 连接视图的更新准则

一:一般准则——(讲)
1任何DML操作,只能对视图中的键值保存表进行更新, 即,“不能通过连接视图修 改多个基表”;
2在DML操作中,“只能使用连接视图定义过的列”;
3“自连接视图”的所有列都是可更新(增删改)的
二:insert准则
1 在insert语句中不能使用“非键值保存表”中的列(包括“连接列”);
2 执行insert操作的视图,至少应该“包含”键值保存表中所有设置了约束的列;
3 如果在定义连接视图时使用了WITH CHECK OPTION 选项,则“不能”针对连接视 图执行insert操作
三:update准则
1键值保存表中的列是可以更新的;
2如果在定义连接视图时使用了WITH CHECK OPTION 选项,则连接视图中的连接列(一般就是“共有列”)和基表中的“其他共有列”是“不可”更新的,连接列和共有列之外的 其他列是“可以”更新的
四:delete准则
1如果在定义连接视图时使用了WITH CHECK OPTION 选项,依然“可以”针对连接视图执行delete操作

3.2.6 可更新连接视图
如果创建连接视图的select查询“不包含”如下结构,并且遵守连接视图的“更新准则”,则这样的连接视图是“可更新”的:

  • 一:集合运算符(union,intersect,minus)
  • 二:DISTINCT关键字
  • 三:GROUP BY,ORDER BY,CONNECT BY或START WITH子句
  • 四:子查询
  • 五:分组函数
  • 六:需要更新的列不是由“列表达式”定义的
  • 七:基表中所有NOT NULL列均属于该视图