视图是从一个或几个基表(或视图)导出的表,它是一个虚表,即数据字典中只存放视图的定义(由视图名和查询语句组成),而不存放对应的数据,这些数据仍存放在原来的基表中。当需要使用视图时,则执行其对应的查询语句,所导出的结果即为视图的数据。因此当基表中的数据发生变化时,从视图中查询出的数据也随之改变了,视图就像一个窗口,透过它可以看到数据库中用户感兴趣的数据和变化。由此可见,视图是关系数据库系统提供给用户以多种角度观察数据库中数据的重要机制,体现了数据库本身最重要的特色和功能,它简化了用户数据模型,提供了逻辑数据独立性,实现了数据共享和数据的安全保密。视图是数据库技术中一个十分重要的功能。
视图一经定义,就可以和基表一样被查询、修改和删除,也可以在视图之上再建新视图。由于对视图数据的更新均要落实到基表上,因而操作起来有一些限制,读者应注意如何才能在视图中正确更新数据。在本章各例中,如不特别说明,以下例子均使用 BOOKSHOP 示例库,用户均为建表者 SYSDBA。
6.1 视图的作用
视图是提供给用户以多种角度观察数据库中数据的重要机制。尽管在对视图作查询和更新时有各种限制,但只要用户对 DM_SQL 语言熟悉,合理使用视图对用户建立自己的管理信息系统会带来很多的好处和方便,归纳起来,主要有以下几点:
1.用户能通过不同的视图以多种角度观察同一数据
可针对不同需要建立相应视图,使他们从不同的需要来观察同一数据库中的数据。
2.简化了用户操作
由于视图是从用户的实际需要中抽取出来的虚表,因而从用户角度来观察这种数据库结构必然简单清晰。另外,由于复杂的条件查询已在视图定义中一次给定,用户再对该视图查询时也简单方便得多了。
3.为需要隐蔽的数据提供了自动安全保护
所谓“隐蔽的数据”是指通过某视图不可见的数据。由于对不同用户可定义不同的视图,使需要隐蔽的数据不出现在不应该看到这些数据的用户视图上,从而由视图机制自动提供了对机密数据的安全保密功能。
4.为重构数据库提供了一定程度的逻辑独立性
在建立调试和维护管理信息系统的过程中,由于用户需求的变化、信息量的增长等原因,经常会出现数据库的结构发生变化,如增加新的基表,或在已建好的基表中增加新的列,或需要将一个基表分解成两个子表等,这称为数据库重构。数据的逻辑独立性是指当数据库重构时,对现有用户和用户程序不产生任何影响。
在管理信息系统运行过程中,重构数据库最典型的示例是将一个基表垂直分割成多个表。将经常要访问的列放在速度快的服务器上,而不经常访问的列放在较慢的服务器上。
例如将 PRODUCT 表分解成两个基表。
PRODUCT(PRODUCTID,NAME,AUTHOR,PUBLISHER,PUBLISHTIME,PRODUCT_CATEGORYID,PRODUCTNO,DESCRIPTION,PHOTO,SATETYSTOCKLEVEL,ORIGINALPRICE,NOWPRICE,DISCOUNT,TYPE,PAPERTOTAL,WORDTOTAL,SELLSTARTTIME,SELLENDTIME),
分解为两个基表:
PRODUCT_1(PRODUCTID,NAME,AUTHOR,PUBLISHER,NOWPRICE)
PRODUCT_2(PRODUCTID,PUBLISHERTIME,PRODUCT_CATEGORYID,PRODUCTNO,DESCRIPTION,PHOTO,SATETYSTOCKLEVEL,ORIGINALPRICE,NOWPRICE,DISCOUNT,TYPE,PAPERTOTAL,WORDTOTAL,SELLSTARTTIME,SELLENDTIME)
并将 PRODUCT 表中的数据分别插入这两个新建表中,再删去 PRODUCT 表。这样一来,原有用户程序中有 PRODUCT 表的操作就均无法进行了。为了减少对用户程序影响,这时可在 PRODUCT_1 和 PRODUCT_2 两基表上建立一个名字为 PRODUCT 的视图,因为新建视图维护了用户外模式的原状,用户的应用程序不用修改仍可通过视图查询到数据,从而较好支持了数据的逻辑独立性。
6.2 视图的定义
语法格式
CREATE [OR REPLACE] [FORCE] VIEW [IF NOT EXISTS]
[<模式名>.]<视图名>[(<列名> {,<列名>})]
AS <查询说明>
[WITH [LOCAL|CASCADED]CHECK OPTION]|[with read only];
<查询说明>::=<表查询> | <连接表>
<表查询>::=<子查询表达式>[ORDER BY子句]
<连接表>::= 请参考第4章 数据查询语句
参数
1.<模式名> 指明被创建的视图属于哪个模式,缺省为当前模式;
2.<视图名> 指明被创建的视图的名称;
3.<列名> 指明被创建的视图中列的名称;
4.<子查询表达式> 标识视图所基于的表的行和列。其语法遵照 SELECT 语句的语法规则;
5.FORCE 选项用于强制创建视图。指定 FORCE 时,基表可以不存在,此时创建视图不报错,但是会报警告,并且创建的视图处于无效状态;
6.WITH CHECK OPTION 此选项用于可更新视图中。指明往该视图中 insert 或 update 数据时,插入行或更新行的数据必须满足视图定义中<查询说明>所指定的条件。如果不带该选项,则插入行或更新行的数据不必满足视图定义中<查询说明>所指定的条件;
[LOCAL|CASCADED] 用于当前视图是根据另一个视图定义的情况。当通过视图向基表中 insert 或 update 数据时,LOCAL|CASCADED 决定了满足 CHECK 条件的范围。指定 LOCAL,要求数据必须满足当前视图定义中<查询说明>所指定的条件;指定 CASCADED,数据必须满足当前视图,以及所有相关视图定义中<查询说明>所指定的条件。
MPP 系统下不支持该 WITH CHECK OPTION 操作。
7.WITH READ ONLY 指明该视图是只读视图,只可以查询,但不可以做其他 DML 操作;如果不带该选项,则根据 DM 自身判断视图是否可更新的规则判断视图是否只读。
图例
视图的定义
语句功能
供 DBA 或该视图的拥有者且具有 CREATE VIEW 权限的用户定义视图。
使用说明
1.当 < 视图名 > 已存在时,若指定 OR REPLACE,则使用新视图替换原同名视图;若指定 IF NOT EXISTS,则忽略本次视图创建操作;若同时指定 OR REPLACE 和 IF NOT EXISTS,则按照 OR REPLACE 的策略执行;若均不指定,则报错;
2.<视图名>后所带<列名>不得同名,个数必须与<查询说明>中 SELECT 后的<值表达式>的个数相等。如果<视图名>后不带<列名>,则隐含该视图中的列由<查询说明>中 SELECT 后的各<值表达式>组成,但这些<值表达式>必须是单纯列名。如果出现以下三种情况之一,<视图名>后的<列名>不能省:
- < 查询说明 > 中 SELECT 后的 < 值表达式 > 不是单纯的列名,而包含集函数或运算表达式;
- < 查询说明 > 包含了多表连接,使得 SELECT 后出现了几个不同表中的同名列作为视图列;
- 需要在视图中为某列取与 < 查询说明 > 中 SELECT 后 < 列名 > 不同的名字。
最后要强调的是:< 视图名 > 后的 < 列名 > 必须全部省略或全部写明。
3.为了防止用户通过视图更新基表数据时,无意或故意更新了不属于视图范围内的基表数据,在视图定义语句的子查询后提供了可选项 WITH CHECK OPTION。如选择,表示往该视图中插入或修改数据时,要保证插入行或更新行的数据满足视图定义中<查询说明>所指定的条件,不选则可不满足;
4.视图是一个逻辑表,它自己不包含任何数据;
5.视图上可以建立 INSTEAD OF 触发器(只允许元组级触发),但不允许创建 BEFORE/AFTER 触发器;
6.视图分为可更新视图和不可更新视图,具体规则参见 6.6 视图数据的更新。
权限
该语句的使用者必须对<查询说明>中的每个表均具有 SELECT 权限。
举例说明
例 1 对 VENDOR 表创建一个视图,名为 VENDOR_EXCELLENT,保存信誉等级为 1 的供应商,列名有:VENDORID,ACCOUNTNO,NAME,ACTIVEFLAG。
CREATE VIEW PURCHASING.VENDOR_EXCELLENT AS
SELECT VENDORID, ACCOUNTNO, NAME, ACTIVEFLAG, CREDIT
FROM PURCHASING.VENDOR
WHERE CREDIT = 1;
由于视图列名与查询说明中 SELECT 后的列名相同,所以视图名后的列名可省。
运行该语句,AS 后的查询语句并未执行,系统只是将所定义的<视图名>及<查询说明>送数据字典保存。对用户来说,就像在数据库中已经有 VENDOR_EXCELLENT 这样一个表。
如果对该视图作查询:
SELECT * FROM PURCHASING.VENDOR_EXCELLENT;
查询结果如下:
VENDORID ACCOUNTNO NAME ACTIVEFLAG CREDIT
---------- --------- -------------------- ---------- -----------
3 00 北京十月文艺出版社 1 1
4 00 人民邮电出版社 1 1
5 00 清华大学出版社 1 1
6 00 中华书局 1 1
7 00 广州出版社 1 1
8 00 上海出版社 1 1
9 00 21世纪出版社 1 1
10 00 外语教学与研究出版社 1 1
11 00 机械工业出版社 1 1
12 00 文学出版社 1 1
用户可以在该表上作数据库的查询、插入、删除、修改等操作。在建好的视图之上还可以再建立视图。
由于以上定义包含可选项 WITH CHECK OPTION,以后对该视图作插入、修改和删除操作时,系统均会自动用 WHERE 后的条件作检查,不满足条件的数据,则不能通过该视图更新相应基表中的数据。
例 2 视图也可以建立在多个基表之上。构造一视图,名为 SALESPERSON_INFO,用来保存销售人员的信息,列名有:SALESPERSONID,TITLE,NAME,SALESLASTYEAR。
CREATE VIEW SALES.SALESPERSON_INFO AS
SELECT T1.SALESPERSONID, T2.TITLE, T3.NAME, T1.SALESLASTYEAR
FROM SALES.SALESPERSON T1, RESOURCES.EMPLOYEE T2, PERSON.PERSON T3
WHERE T1.EMPLOYEEID = T2.EMPLOYEEID AND T2.PERSONID = T3.PERSONID;
如果对该视图作查询:
SELECT * FROM SALES.SALESPERSON_INFO;
查询结果如下:
SALESPERSONID TITLE NAME SALESLASTYEAR
------------- -------- ---- -------------
1 销售代表 郭艳 10.0000
2 销售代表 孙丽 20.0000
由前面的介绍可知,基表中的数据均是基本数据。为了减少数据冗余,由基本数据经各种计算统计出的数据一般是不存贮的,但这样的数据往往又要经常使用,这时可将它们定义成视图中的数据。
例 3 在 PRODUCT_VENDOR 上建立一视图,用于统计数量。
CREATE VIEW PRODUCTION.VENDOR_STATIS(VENDORID, PRODUCT_COUNT) AS
SELECT VENDORID, COUNT(PRODUCTID)
FROM PRODUCTION.PRODUCT_VENDOR
GROUP BY VENDORID
ORDER BY VENDORID;
在该语句中,由于 SELECT 后出现了集函数 COUNT(PRODUCTID),不属于单纯的列名,所以视图中的对应列必须重新命名,即在<视图名>后明确说明视图的各个列名。
由于该语句中使用了 GROUP BY 子句,所定义的视图也称分组视图。分组视图的<视图名>后所带<列名>不得包含集函数。
如果对该视图作查询:
SELECT * FROM PRODUCTION.VENDOR_STATIS;
查询结果如下:
VENDORID PRODUCT_COUNT
----------- --------------------
5 1
6 2
7 1
8 1
9 1
10 1
11 1
6.3 视图的删除
一个视图本质上是基于其他基表或视图上的查询,我们把这种对象间关系称为依赖。用户在创建视图成功后,系统还隐式地建立了相应对象间的依赖关系。在一般情况下,当一个视图不被其他对象依赖时可以随时删除视图。
语法格式
DROP VIEW [IF EXISTS] [<模式名>.]<视图名> [RESTRICT | CASCADE];
参数
1.<模式名> 指明被删除视图所属的模式,缺省为当前模式;
2.<视图名> 指明被删除视图的名称。
图例
视图的删除
使用说明
- 删除不存在的视图会报错。若指定 IF EXISTS 关键字,删除不存在的视图,不会报错;
- 视图删除有两种方式:RESTRICT/CASCADE 方式。其中 RESTRICT 为缺省值。当设置 dm.ini 中的参数 DROP_CASCADE_VIEW 值为 1 时,如果在该视图上建有其它视图,必须使用 CASCADE 参数才可以删除所有建立在该视图上的视图,否则删除视图的操作不会成功;当设置 dm.ini 中的参数 DROP_CASCADE_VIEW 值为 0 时,RESTRICT 和 CASCADE 方式都会成功,且只会删除当前视图,不会删除建立在该视图上的视图;
- 如果没有删除参考视图的权限,那么两个视图都不会被删除;
- 该视图删除后,用户在其上的权限也均自动取消,以后系统中再建的同名视图,是与他毫无关系的视图。
权限
使用者必须拥有 DBA 权限或是该视图的拥有者。
举例说明
例 1 删除视图 VENDOR_EXCELLENT,可使用下面的语句:
DROP VIEW PURCHASING.VENDOR_EXCELLENT;
当该视图对象被其他对象依赖时,用户在删除视图时必须带 CASCADE 参数,系统会将依赖于该视图的其他数据库对象一并删除,以保证数据库的完整性。
例 2 删除视图 SALES.SALESPERSON_INFO,同时删除此视图上的其他视图,可使用下面的语句:
DROP VIEW SALES.SALESPERSON_INFO CASCADE;
6.4 视图的查询
视图一旦定义成功,对基表的所有查询操作都可用于视图。对于用户来说,视图和基表在进行查询操作时没有区别。
例 1 从 VENDOR_EXCELLENT 中查询 ACTIVEFLAG 为 1 的供应商的编号和名称。
SELECT VENDORID, NAME FROM PURCHASING.VENDOR_EXCELLENT WHERE ACTIVEFLAG = 1;
系统执行该语句时,先从数据字典中取出视图 VENDOR_EXCELLENT 的定义,按定义语句查询基表,得到视图表,再根据条件:ACTIVEFLAG = 1 查询视图表,选择所需列名,得到结果。
查询结果如下:
VENDORID NAME
----------- --------------------
3 北京十月文艺出版社
4 人民邮电出版社
5 清华大学出版社
6 中华书局
7 广州出版社
8 上海出版社
9 21世纪出版社
10 外语教学与研究出版社
11 机械工业出版社
12 文学出版社
视图尽管是虚表,但它仍可与其它基表或视图作连接查询,也可以出现在子查询中。
例 2 查询信誉等级为 1 的供应商供应的图书编号、名称、通常价格和供应商名称。
SELECT T1.PRODUCTID, T1.NAME, T2.STANDARDPRICE, T3.NAME
FROM PRODUCTION.PRODUCT T1, PRODUCTION.PRODUCT_VENDOR T2, PURCHASING.VENDOR_EXCELLENT T3
WHERE T1.PRODUCTID = T2.PRODUCTID AND T2.VENDORID = T3.VENDORID;
系统执行该语句时,先从数据字典中取出视图 VENDOR_EXCELLENT 的定义,按定义语句查询基表,得到视图表,再将 PRODUCT、PRODUCT_VENDOR 和视图表按连接条件作连接,选择所需列名,得到最后结果。
查询结果如下:
PRODUCTID NAME STANDARDPRICE NAME
----------- ------------------------- ------------- --------------------
7 数据结构(C语言版)(附光盘) 25.0000 清华大学出版社
8 工作中无小事 25.0000 机械工业出版社
9 突破英文基础词汇 25.0000 外语教学与研究出版社
10 噼里啪啦丛书(全7册) 25.0000 21世纪出版社
3 老人与海 25.0000 上海出版社
4 射雕英雄传(全四册) 25.0000 广州出版社
1 红楼梦 25.0000 中华书局
2 水浒传 25.0000 中华书局
6.5 视图的编译
一个视图依赖于其基表或视图,如果基表定义发生改变,如修改或删除一列,或者视图的相关权限发生改变,可能导致视图无法使用。在这种情况下,可对视图重新编译,检查视图的合法性。
语法格式
ALTER VIEW [<模式名>.]<视图名> COMPILE;
参数
1.<模式名> 指明被编译视图所属的模式,缺省为当前模式;
2.<视图名> 指明被编译视图的名称;
图例
视图的编译
使用说明
对视图的定义重新进行分析和编译,如果编译出错,则报错,可以此判断视图依赖的基表是否已被删除或修改了表定义。
权限
使用者必须拥有 DBA 权限或是该视图的拥有者。
举例说明
例 重新编译视图 PURCHASING.VENDOR_EXCELLENT。
ALTER VIEW PURCHASING.VENDOR_EXCELLENT COMPILE;
6.6 视图数据的更新
视图数据的更新包括插入(INSERT)、删除(DELETE)和修改(UPDATE)三类操作。由于视图是虚表,并没有实际存放数据,因此对视图的更新操作均要转换成对基表的操作。在 SQL 语言中,对视图数据的更新语句与对基表数据的更新语句在格式与功能方面是一致的。
例 1 从视图 VENDOR_EXCELLENT 中将名称为人民邮电出版社的 ACTIVEFLAG 改为 0。
UPDATE PURCHASING.VENDOR_EXCELLENT
SET ACTIVEFLAG = 0 WHERE NAME = '人民邮电出版社';
系统执行该语句时,首先从数据字典中取出视图 VENDOR_EXCELLENT 的定义,将其中的查询说明与对视图的修改语句结合起来,转换成对基表的修改语句,然后再执行这个转换后的更新语句。
UPDATE PURCHASING.VENDOR SET ACTIVEFLAG = 0 WHERE NAME = '人民邮电出版社' AND CREDIT = 1;
例 2 往视图 VENDOR_EXCELLENT 中插入一个新的记录,其中 ACCOUNTNO 为 00,NAME 为电子工业出版社,ACTIVEFLAG 为 1,CREDIT 为 1。则相应的插入语句为:
INSERT INTO PURCHASING.VENDOR_EXCELLENT(ACCOUNTNO, NAME, ACTIVEFLAG, CREDIT) VALUES('00 ', '电子工业出版社', 1, 1);
例 3 从视图 VENDOR_EXCELLENT 中删除名称为中华书局的供应商信息。
DELETE FROM PURCHASING.VENDOR_EXCELLENT WHERE NAME = '中华书局';
系统将该语句与 VENDOR_EXCELLENT 视图的定义相结合,转换成对基表的语句:
DELETE FROM PURCHASING.VENDOR WHERE NAME='中华书局' AND CREDIT=1;
系统执行该语句,会报告违反约束错误,因为 VENDOR_EXCELLENT 尽管是视图,在做更新时一样要考虑基表间的引用关系。PRODUCT_VENDOR 表与 VENDOR 表存在着引用关系,PRODUCT_VENDOR 表为引用表,VENDOR 表为被引用表,只有当引用表中没有相应 VENDORID 时才能删除 VENDOR 表中相应记录。
在关系数据库中,并不是所有视图都是可更新的,即并不是所有的视图更新语句均能有意义地转换成相应的基表更新语句,有些甚至是根本不能转换。例如对视图 VENDOR_STATIS:
UPDATE PRODUCTION.VENDOR_STATIS SET PRODUCT_COUNT=3 WHERE VENDORID=5;
由于产品数量是查询结果按供应商编号分组后各组所包含的行数,这是无法修改的。像这样的视图为不可更新视图。
目前,不同的关系数据库管理系统产品对更新视图的可操作程度均有差异。在 DM 中,包含以下情况的视图不支持更新:
- 集合运算;
- 分组、集函数、HAVING 子句、层次查询、TOP 子句、ROWNUM;
- 不可更新视图、外部表、物化视图辅助表、位图连接索引辅助表、自定义的统计信息表、系统表;
- 超过 128 个表对象;
- INI 参数 ENABLE_DIST_VIEW_UPDATE 为 0 时,含有 DISTINCT;
- INI 参数 MULTI_UPD_OPT_FLAG 不包含 2 时,含有多表连接;或多表连接条件不包含聚集主键;
- 视图定义中包含 TOP、LIMIT、ROW_LIMIT 子句;
- 在 TABLE 函数所得表之上建立的视图;
- 在不允许更新视图之上建立的视图。