1. 视图的定义:
a. 视图是一种导出表,可以有基本表到导出也可以由视图本身导出,当然也可以由这两种共同导出;
b. 视图是一种虚表,没有任何数据,只有视图的定义(定义就是如何从其他表中导出),其真正的数据还是存放在基本表中;
c. 因此如果基本表改变了,那么在查询视图时里面的数据也将会发生改变;
d. 视图就像一种查询命令(和DOS命令一样),而这个命令的内容就是用一种指定的方法去观察基本表中的数据;
e. 视图和基本表一样也提供了相同的操作,但是对于更新操作来说(增、删、改等)限制很强,比较麻烦;
2. 建立视图:
a. 使用CREATE VIEW关键字;
b. 一般规则:
CREATE VIEW 视图名
(为视图取的列名的列表)
AS
子查询
[WITH CHECK OPTION]
!!!注意:子查询中不允许有ORDER BY和DISTINCT关键字,否则会报错!!!
c. 子查询结果中的列必须和视图中的列一一对应,视图中的列用户可以自己为其取适当的名字,就相当于给子查询中的列取别名作为视图的列名;
d. 创建时视图的列名不完全需要一一列出,只有在如下情况时必须全部列出:
i. 子查询的结果的列含有表达式(包括聚集函数表达式的);
ii. 子查询是多表连接并且子查询的列名中含有同名列,此时必须为视图的这两列另取名字以示区别;
iii. 需要为视图的列重新取名字;
注:如果视图的列名不写则视图的列名默认为和子查询的列名一样!!!
e. WITH CHECK OPTION该项可写可不写,它表示在进行UPDATE、INSERT、DELETE时必须满足视图定义中的WHERE条件,这个选项会对视图的操作增加限制,可以时安全性增加;
f. 建立信息系学生的视图:
CREATE VIEW IS_Student //没指定视图的列名,那么就默认列名为子查询的列名Sno, Sname, Sage
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS'
WITH CHECK OPTION //这里就规定了再对表进行操作的时候必须保证元组的系一定为IS
注意:创建完了视图以后并不会立即执行里面的SELECT语句,而是将视图的定义存入数据字典,只有用户使用SELECT语句查询视图的时候才会执行试图定义中的查询语句;
g. 单表视图和行列子集视图:
i. 单表视图就是由一张表导出来的视图;
ii. 行列子集视图就是去掉了基本表中一些行一些列但保留了主码的单表视图,上面的IS_Student就是一张行列子集视图;
h. 多表视图:建立信息系选修了1号课程的学生的视图:
CREATE VIEW IS_S1
(Sno, Sname, Grade) //多表查询并且子查询存在相同的列名,为不是命名冲突必须为视图的列重新取名
AS
SELECT Student.Sno, Sname, Grade
FROM Student, SC
WHERE Student.Sno = SC.Sno AND
Cno = '1' AND
Sdept = 'IS'
i. 在视图上建立视图:建立信息系选修1号课程并且成绩在90分以上的学生的视图:
CREATE VIEW IS_S2
AS
SELECT Sno, Sname, Grade
FROM IS_S2 //基于视图1
WHERE Grade > 90
j. 带表达式的视图(带虚拟列):
a. 子查询中可以存在带列表达式的查询,由于这些带表达式查询出来的列在原来的基本表中不存在,系统也不会保存,并且如果将其导入到一张视图中(视图只是定义而没有真正的数据),因此像这样的列在视图中称为虚拟列,带虚拟列的视图被称为带表达式的视图;
b. 定义一个反映学生出生年份的视图:
CREATE VIEW BT_S
(Sno, Sname, Sbirth)
AS
SELECT Sno, Sname, 2004 - Sage
FROM Student
c. 将学生的学号和其平均成绩定义为一张视图:
CREATE VIEW S_G
(Sno, Gavg) //子查询中包含聚集函数表达式因此必须为视图定义列名
AS
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno
d. 一种容易被破坏的映像结构(子查询中使用通配符*):将Student表中所有女生记录定义为一个视图
CREATE VIEW F_Student
(F_sno, name, sex, age, dept) //由于这里认为定义了视图的列,因此列的个数和顺序都是固定的!!
AS
SELECT * //但是子查询使用的是通配符,一旦基本表中的列被重新设计或者被更改,可能会导致列的顺序或者列的数量和视图的不匹配
FROM Student //因此在这种情况下必须先删除原视图,再根据修改或者被重新设计过的基本表重新定义该视图
WHERE Ssex = '女'
3. 删除视图:
a. 一般规则:DROP VIEW 视图名 选项
b. 选项仍然是CASCADE和RESTRICT,在缺省情况下默认为RESTRICT;
c. 级联删除:
i. 如果其他视图由待删除视图导出,则不能直接删除(相当于RESTRICT),否则将会导致报错(在RESTRICT或者缺省的情况下);
ii. 必须使用CASCADE关键字执行级联删除,删除该视图的同时也会删除由它导出的其他视图;
注:对于表的删除也使用,如果有视图或者其他表由待删除的表导出,则也可以使用CASCADE关键字将这些导出对象也一并删除;
!!但是,和视图不一样的地方是基本表的删除不用RESTRICT的话可以忽视导出对象的级联,也就是说表删除了以后那些由它导出的对象的定义(特别是视图)并不会从数据字典中删除,但是要查询这些导出对象将会发生错误,所以如果要级联删除表就一定要加CASCADE;
d. 删除BT_S和IS_S1:
DROP VIEW BT_S
DROP VIEW IS_S1 CASCADE //IS_S2有前者导出,因此需要用到级联删除,这样IS_S2也被同时删除
4. 视图查询:
a. 可以像查询基本表一样地来查询视图;
b. 查询信息系学生视图中年龄小于20岁的学生:
SELECT Sno, Sage
FROM IS_Student
WHERE Sage < 20
c. 视图消解:就是指对视图的查询过程,是这样的,系统会先从数据字典中调用视图的定义,然后将视图中的子查询定义和对视图查询中的主查询结合起来转换成等价的对基本表的查询;
!!因此,视图的作用就有点类似批处理,可以将一个复杂的查询定义为视图,再对该视图进行查询,总体上就能构成一种更加复杂的查询(类似脚本编程);
d. 查询选修了1号课程的信息系的学生:
SELECT SC.Sno, Sname
FROM IS_Student, SC
WHERE IS_Student.Sno = SC.Sno AND Cno = '1'
e. 视图消解存在问题的视图查询:S_G中查询平均成绩在90分以上的学生的学号和平均成绩
SELECT Sno, Gavg
FROM S_G
WHERE Gavg > 90
但是其对基本表的等价转换为:
SELECT Sno, AVG(Grade)
FROM SC
WHERE AVG(Grade) > 90 //WHERE中使用了聚集函数表达式,因此不能正确转换
GROUP BY Sno
!!但是现在大多数现代数据库都能对这类行列子集视图能正确转换,但是对于非行列子集视图(不包含主码)不一定能进行这样的转化(大多数都是不可以的)!!
5. 视图更新:
a. 既然对视图更新,那么用户当然希望更新后的查询结果能体现出之前的更新,因此视图的更新是直接加在基本表上的,只不过是通过视图的定义(这个中间桥梁)对基本表进行更新,而这种间接的过程也是通过视图的消解实现的;
b. 因此可以看到视图并不仅仅是一张虚表,也是一种快捷、方便、简化的对基本表操作的介质;
c. 为了在更新时不超出视图中定义的数据的范围,需要在创建视图时使用WITH CHECK OPTION;
d. 将信息系中学号为200215122的学生的名字改为“刘辰”:
UPDATE IS_Student
SET Sname = '刘辰'
WHERE Sno = ‘200215122’
其消解结果为:
UPDATE Student
SET Sname = ‘刘辰’
WHERE Sno = ‘200215122’ AND Sdept = ‘IS’
e. 向信息系视图中插入一条新纪录:
INSERT INTO IS_Student
VALUES('200215129', '赵新', 20)
f. 删除视图:删除信息系视图中学号为200215129的记录
DELETE IS_Student
WHERE Sno = ‘200215129’
6. 不可更新的视图——非行列子集视图:
a. 除了不包含主码外非行列子集视图还具有如下特征,正因为这些特征导致这些视图无法更新:
i. 定义中的子查询含有列的表达式(包括聚集函数表达式),特别是含有聚集函数表达式的,如果对该视图进行更新,比如虽然可以更改平均成绩,但是该如何更改基本表中的各项成绩才能是平均成绩刚好等于修改后的平均成绩呢?因此这种情况是无法修改的,这种情况在数据库实现上就已经被拒绝了;
ii. 同理,如果定义视图的子查询存在嵌套查询,不管在那一层出现了表达式也同样无法对该视图进行更新(原理同上);
iii. 有两个及两个基本表导出的视图(也属于非行列子集视图,因为行列子集视图是由单表导出的);
iv. 定义视图的子查询中包含GROUP BY语句;
v. 由非行列子集视图导出的视图;
b. 将S_G中学号为200215121的学生的平均成绩改为90:
无法操作,因为S_G表为非行列子集表(导出关系中含有平均函数)!!!