数据库的真实数据都是存在于数据表中,数据表是反映现实世界的实体关系。但是,为现实世界的所有关系创建数据表是不现实的。数据库中的视图解决了这一问题。视图以物理数据未基础,利用更灵活的策略来实现关系。接下来,我们将从:
视图介绍、关系视图的创建和使用、内嵌式图的使用、对象视图的使用、物化视图的使用等几个方面,
来学习视图的知识,并掌握如何创建和使用各种视图,同时对各种视图之间的区别有清晰的了解。
1、视图简介:
1.1 什么是视图
视图是由已经存在的数据,通过一定的运算规则,来获得新的数据集合。这使得用户可以更加灵活的自定义数据集合,视图同时为数据安全性提供了一种控制策略。
(1) 视图的产生
之前一篇博文中讲到了数据表的创建规则,由于遵循第三范式,表在设计时,应当避免数据冗余,而另一方面,使用各种组合数据更加常用,设计规则却禁止为组合数据创建新的数据表。
比如:表employees存储了员工的基本信息,其中包括了员工ID、员工姓名、职位、年龄、地址。表salary存储了员工工资信息,其中包括了工资ID、员工ID、月份、工资、货币种类。
现在需要为财务人员准备一个新的数据集合,该数据集合存储了员工ID、员工姓名、员工年龄、月份及当月工资。很明显,创建新表employee_salary,以满足财务人员的需求是不可取的,此时,创建视图来解决该问题是最佳途径。
下图演示了针对表employees每行数据,根据employee_id列值相等的条件,在表salary中筛选记录,并最终组成新的数据集合。这种关系运算的存储在视图vw_employees终。对于用户来说,只需要定义运算规则,而运算贵的载体-----视图,并不存储真实的数据。
(2)视图的本质
从关系代数理论上来说,数据表可以看做关系。这种关系往往代表了现实世界的真实实体。而关系可以通过各种运算(交、差、并、投影)来获得新的关系。
在查询员工工资状况的实例中,可以通过表之间的关系运算获得财务人员所需的结果集合。该结果集具有临时性,一旦使用完毕,即可丢弃。这些结果数据,并不形成真正的数据表,也不会持久化到数据库中。视图也不存储查询的结果,但是存储了查询的定义。也就是说,对于关系运算的运算步骤进行存储。因此,视图的本质就是关系运算的定义。
1.2 为啥使用视图咧
视图是绝大部分数据库开发中都会使用的概念。使用视图大致有两个方面的原因。
(1)封装查询
数据库虽然可以存储海量数据,但是在数据表设计上却不可能为每种关系创建数据表。例如:对于学生表,存储了学生信息,学生的属性包括学号、姓名、年龄、地址等信息;而学生成绩表只存储了学生学号、科目、成绩等信息,现需要获得学生姓名及成绩信息,那么久需要创建一个关系,该关系需要包含学生姓名、科目、成绩。但为该关系创建一个新的数据表,并利用实际信息进行填充,以备查询使用,是不合适的。因为这种做法很明显的造成了数据库中数据的大量冗余。
视图则是解决该问题的最佳策略,因为视图可以存储查询定义(或者关系运算),那么,一旦使用视图存储了查询定义,就如同存储了一个新的关系。用户可以直接对视图中所存储的关系进行各种操作,就如同面对的是真实的数据表。
(2)灵活的控制安全性
一个数据表可能含有很多列,但是这些列的信息,对于不同角色的用户,可访问的权限有可能不同。例如:在员工表中,可能存在着员工工号、姓名、年龄、职位、地址、社会关系等信息。对于普通用户,有可能需要访问员工表,来查看某个工号的员工的姓名、职位等信息,而不允许查看家庭地址、社会关系等信息;对于高级用户,则需要关注所有信息,那么,久涉及到数据表的安全性。
利用视图可以灵活的实现这一策略,例如:可以首先创建名为vw_employees的视图,该视图的查询定义为,选择员工表中员工工号、姓名、职位等3列,这相当于在员工关系中,进行投影运算,即选择员工工号、姓名、职位等3个属性,形成新的关系。
同样的,对于高级用户,可以创建名为vw_employees_hr的视图,该视图选择员工表中所有列。
然后,对于两种角色分别分配两个视图的查询权限,与实际的数据表employees隔离开来,从而控制数据访问的安全性。
2、创建和使用关系视图
oracle中的视图,按照创建和使用方式的不同,可以分为四类:关系视图、内嵌视图、对象视图和物化视图。
关系视图是4种视图中最简单,同时也最常用的视图。关系视图可以看做对简单或复杂查询的定义。他的输出可以看做一个虚拟的表。
2.1 创建关系视图
oracle视图是作为数据库对象存在的。因此,创建之后也可以通过工具或数据字典来查看视图的相关信息,接下来,要讲解的是:关系视图的创建和如何查看视图的属性信息。
(1)创建关系视图
创建关系视图应该使用create view命令,其语法形式如下所示:
create view 视图名称 as 查询语句|关系运算
其中,create view是创建关系视图的命令,其后紧跟视图名称;as 后面连接的是视图的查询定义(或者说关系运算)。
例子:在数据库中存在着名为employees的数据表,如需创建针对普通用户的视图vw_employees。该视图仅可以访问表中的员工ID、员工姓名,以及员工职位,那么可以利用如下的SQL语句。
create view vw_employees as select employee_id, employee_name, employee_position from employees;
其中,create view 向数据库发送创建视图命令,as 关键字连接创建命令与视图定义;select employee_id、employee_name和employee_position from t_employees用于获取表t_employees中的employee_id、employee_name和employee_position 3 列。
(2)查看视图定义
视图一旦创建,其定义即可存在于数据库中,可以通过PL/SQL Developer的veiws 窗口查看视图VW_EMPLOYEES在数据库中的信息。
如果是有数据字典,也可以在输入SQL语句进行查询,比如:
select view_name, text from user_views where view_name= 'VW_EMPLOYEES';
view text
vw_employee select employee_id, employee_name, employee_position from employees
其中,view_name列为视图名称,text列为视图定义。
2.2 使用关系视图
视图一旦创建,用户可以像查询数据表一样查询视图中的数据,但是,对于插入和更新操作来说,情况则有些不同。
(1)查询视图
例子:在创建了视图VW_EMPLOYEES之后,即可利用查询语句来获得视图中所包含的数据,如下:
SQL>select * from vw_employeess;
(2)更新视图数据
用户可以利用update语句更新视图中的数据,而视图本身并不存储数据,其数据来源于基础数据表,因此,更新视图数据,实际是更新基础表中的数据。
例子:在员工视图vw_employees中,现在需要将员工“刘俊”职位调整为“高级工程师”,那么可以直接更新视图,响应的SQL语句:
SQL>update vw_employees set employee_position = '高级工程师' where employee_name='刘俊';
其中,update为更新命令;vw_employees为update 命令的操作对象;set employee_position = '高级工程师',employee_name='刘俊',是指定更新条件。
但是,此时更新的实际是将表employees中的数据进行了修改。
综合视图操作及查询结果可知,对视图的更新操作,实际为更新基础表中的数据,由于视图仅存储查询定义,因此,一旦基础表中的数据被修改,则修改后的结果可以立即反映到视图中。
2.3 向视图插入数据
同样,可以利用insert语句,向视图中插入数据。
例子:在视图vw_employees中,插入新员工“张三”的相关信息,其SQL语句如下所示。
SQL>insert into vw_employees values (6 , '张三', '测试工程师')
由于,该视图只能查到该3项内容,所以,在向视图vw_employees中插入数据时,无法为列employee_age和列employee_address指定数据,因此,在基础表employees中,对应记录的employee_age列和employee_address列的值为空。
2.4 总结利用关系视图修改数据。
利用关系视图,除了插入数据和更新数据之外,还可以删除其中的数据。表面上看起来,可以通过视图对基础表进行任何修改,但事实并非如此,与之相反,大多数时候,并不能直接利用视图修改基础表数据。
例子:oracle内置视图user_update_columns定义了用户视图中各列的可更新情况,可以通过如下SQL语句进行查看。
SQL>select table_name, column_name, updatable, insertable, deletable
from user_updatable_columns
where table_name = 'VW_EMPLOYEES'
其中,TABLE_NAME列为表名(在此,为视图名,这里也印证了oracle往往将视图当做普通数据表处理);COLUMN_NAME列为视图中的列名;UPDATBALE、INSERTABLE和DELETABLE分别代表列的可更新、可插入以及可删除的情况。
对于更新操作,只要该列可更新,那么饥渴利用视图进行更新;而对于插入和删除操作,则必须所有列均可执行插入和删除操作,才能利用视图进行操作。
2.3 修改/删除视图
在创建了关系视图vw_employees之后,可以对其进行修改和删除操作。
(1)修改视图
修改视图的过程即为重新定义视图的过程。可以通过首先删除视图,然后再次创建实现。另外,oracle也提供了一个专门的命令----create or replace view 来重新定义视图。其语法形式如下所示:
create or replace view 视图名称 as 查询语句 | 关系运算
例子:假设现在需要为视图vw_employees添加新列employee_age,那么可以利用如下SQL语句。
create or repalce view vw_employees as
select employee_id, employee_name, employee_position, employee_age from employees
其中,create or replace view vw_employees用于创建或者替换视图vw_employees的定义;as 之后的查询语句为视图的新定义,在新定义中增加了列employee_age。
【注意】create or replace view命令的作用,当同名视图不存在时,将执行创建命令;否则将执行替换命令。
(2)删除视图
删除视图的动作实际为删除数据库中的对象操作,因此该操作为DML操作,如同删除数据表对象,删除视图也应该使用drop命令,其语法形式如下所示。
drop view view_name
其中,drop view向数据库发送删除视图命令;view_name则指定了要删除的视图名称。
例子:如需删除视图vw_employees,则可以利用如下SQL语句。
drop view vw_employees;
2.4 只读视图
上面讲述了修改视图数据,有时,并不希望用户通过视图修改数据,则可以创建只读视图,创建只读视图应该使用read only选项,其基本语法形式如下所示。
create or replace view 视图名称 as查询语句
with read only
其中,with read only 选项表示该视图将被创建为只读视图。
2.5 联接视图
对于视图定义来说,其数据可以来源于一个数据表,也可以来源多个数据表或者其他视图的联接。事实上,联接视图在实际开发中更加常用,本节将讲述联接视图的使用。
例子:可以利用create or replace view定义一个联接视图,只是视图定义更加复杂而已,在表employees与表salary中分别定义了员工与工资信息,则可以利用create or replace view创建视图。
create or replace view vw_employee_salary as
select e.employee_id, e.employee_name, s.month, s.salary
from employees e, salary s
where e.employee_id = s.employee_id
其中as关键字之后使用了表employees与表salary的联接获得新的数据集合。联接条件为表employees中的employee_id与表salary中的employee_id相等。在视图创建成功之后,即可查询表中的数据。
2.6 强制创建视图
归根结底,视图数据的来源是基础数据表。有时,视图的基础表尚未创建,但是仍然希望创建基于不存在的数据表的视图。
例子:开发者预期有名为customer的数据表,该表至少包含以下列。
现需要创建一个名为vw_customer的视图,该视图仅包含以下列customer_id、customer_code、customer_name、customer_level和contact_telephone。但是,视图创建者无权创建实际的数据表。但是又不能等待表的预期创建者的工作,此时,可以使用force选项来强制创建视图。利用force选项,强制创建视图的语法如下所示。
create or replace force view 视图名称 as 查询语句 | 关系运算
在PL/SQL Developer中强制创建视图vw_customer。
SQL>create or replace force view vw_customer as
select customer_id, customer_code, customer_name, contact_telephone
from customer;