对于用户来说,视图看起来与表相似,两者都是二维行列结构,并且用户可以在视图上运行SELECT语句和DML语句。程序员知道视图的真相:视图只不过是SELECT语句。任何SELECT语句都返回二维行集。如果将SELECT语句保存为视图,那么每当用户查询或更新视图(给人的印象就是表)中的行时,就会像对待表一样运行语句并向用户显示结果。视图可以基于任何SELECT语句。可以使联接表、执行聚合或进行排序的语句,可以使用在SELECT命令中合法的任何内容。
注意:视图与表共享相同的名称空间:在可以使用表名的任何位置,使用视图名在语法上也是正确的。
1.使用视图的原因
使用视图可能的原因包括:安全性、简化用户SQL语句、防止错误、提高性能和使数据易于理解。表和列名往往太长,而且相当无意义。视图和其中的列则更为一目了然。
1.用来实施安全性的视图
有时可能只应当允许用户看到表的部分行和列。虽然有几种方式可以做到这一点,但是视图往往是最简单的方式。以HR.EMPLOYEES
表为例,这个表中包括不应让除人事部门之外的员工看到的个人详细信息。但是财务工作人员需要能够看到成本核算信息。该视图将对数据做出客观处理:
create view hr.emp_fin as select hire_date,job_id,salary,commission_pct,department_id from hr.employees;
注意,上面对表使用了模式限定符作为数据(常常是指基表或明细表)和视图的来源:视图是模式对象,可以从相同模式或其他模式的表中取得所需的数据。如果没有指定模式,则就是当前模式。
然后可以授予财务人员查看视图而不是表的权限,并且可以执行如下语句:
select * from emp_fin where department_id=50;
他们只能看到组成该视图的5列,而看不到EMPLOYEES中其余包含个人信息的列。可以像表一样将该视图与其他表联接或执行聚合操作:
select department_name,sum(salary) from departments natural join emp_fin group by department_name;
构造良好的视图集可以在数据库中实现完整的安全结构,给予用户访问他们需要查看的数据的权限,而隐藏他们不需要查看的数据。
2.用来简化用户SQL的视图
对用户来说,如果复杂的工作(如联接或聚合)都由定义视图的代码完成,那么用户查询数据时就会轻松很多。在上面的示例中,用户必须编写将EMP_FIN视图联接到DEPARTMENTS表的代码,并计算每个部门薪水的总和。可以在一个视图中完成全部这些工作:
create view dept_sal as select d.department_name,sum(e.salary) from departments d left outer join employees e on d.department_id = e.department_id group by department_name order by department_name;
然后用户可以从DEPT_SAL中选择,而不需要知道关于联接的任何情况,甚至不需要知道如何排序结果:
select * from dept_sal;
3.用来防止错误的视图
虽然不可能防止用户犯错误,但是构造良好的视图可以防止一些由于不了解应如何解释数据而产生的错误。视图有助于按照没有歧义的方式提供数据。例如,很多应用程序永远不会真正删除行。考虑下面这个表:
create table emp(empno number constraint emp_empno_pk primary key,ename varchar2(10),deptno number,active varchar2(1) default 'Y');
列ACTIVE是一个标志,表示该员工当前被雇佣,当插入一行时,这个标志的默认值为‘Y’。当用户通过用户界面‘删除’员工时,底层SQL语句将更新为把ACTIVE设置为‘N’。如果不了解这一点的用户对表进行查询时,他们可能会严重曲解结果。因此,授予他们对视图的访问权限往往会更好:
create view current_staff as select * from emp where active='Y';
访问这个视图的查询不可能看到‘已删除的’员工成员。
4.使数据易于理解的视图
数据库中的数据结构是规范化表。期望用户理解规范化结构是不合理的要求。以Oracle E-Business套件为例,Accounts Receivable模块中的customer实际上是一个整体,由分布在HZ_PARTIES、HZ_PARTY_SITES及HZ_CUST_ACCTS_ALL等表中的信息组成。所有这些表用主键到外键的关系联接,但是这些关系没有在任何对用户可见的标识符上定义:它们基于用户永远见不到的列,其中包含按照顺序在内部生成的值。用来检索客户信息的表单和报表永远不会直接访问这些表,它们都是通过视图工作的。
视图除了可以通过易于理解的形式向用户提供数据之外,也提供用户看到的对象和存储在数据库中的对象之间的抽象层,对于维护工作相当有价值。视图允许在不需要重新编码应用程序的情况下重新设计数据结构。如果修改了表,那么调整视图定义可能对SQL和PL/SQL代码造成一些不必要的改动。视图是使应用程序能够在不同数据库之间移植的重要技术。
5.用来提升性能的视图
程序员可以优化视图背后的SELECT语句,这样用户就不需要关心代码的调整。得到同一个结果可能有很多方式,但是有些技术也许比其他技术慢很多。例如,当联接两个表时,通常可以选择嵌套循环联接,也可以选择哈希联接。嵌套循环联接使用索引找到单个行,哈希联接将整个表读入内存中。在这两种方法之间如何选择取决于数据和可以硬件资源的状态。
从理论上讲,人们总是能依靠Oracle优化器来找出运行SQL语句的最佳方式,但是有时也会出错。如果程序员知道哪种技术最好,可以通知优化器采用这种技术,本例强制使用哈希技术:
select view dept_emp as select /* + USE_HASH (employees departments) */ department_name,last_name from departments natural join employees;
每当用户查询DEPT_EMP视图时,都会通过将明细表扫描到内存中来进行联接。
2.简单视图和复杂视图
出于实用的目的,简单视图和复杂视图的划分与是否能对视图执行DML语句有关:简单视图通常能接受DML语句,复杂视图则不能。严格的定义如下所示:
1.简单视图从明细表中取得数据,不使用函数,不进行聚合。
2.复杂视图可以联接明细表、使用函数和进行聚合。
一般不能对复杂视图执行DELETE、INSERT、UPDATE命令。视图中的行对明细表中的行进行反向映射,但是这种映射并不总是能够一对一地建立,而这对于DML操作是必须的。一般来说可以对简单视图执行DML,但并非总是如此。例如,如果视图不包括具有NOT NULL约束的列,那么通过视图进行INSERT操作就不会成功(除非该列有默认值)。这样会产生令人不安的影响,因为错误消息会引用语句中没有提到的表和列。