视图简介
基本概念
- 基本表:是实际存储于存储文件中的表,基本表中的数据是需要存储的。
- 视图:是在SQL中只存储其由基本表导出视图所需要的公式,即由基本表产生视图的映像信息,其数据并不存储,而是在运行过程中动态产生与维护的。对视图数据的更改最终要反映在对基本表的更改上。
视图的作用
-
数据库视图隐藏了数据的复杂性。,让数据更加清晰。想要什么样的数据,就创建什么样的视图。
-
数据库视图有利于控制用户对表中某些列的访问。可以对不同的用户,设定不同的视图。
-
数据库视图使用户查询变得简单。视图就像一个函数,提高了各种操作的重用性。
视图的基本操作
以下操作都是基于sql server2016进行测试的。
视图的创建
视图需要“先定义,在使用”,简单来说就是在select查询语句前加上创建视图的语句,如下所示:
create view <视图名> [<列名>,<列名>...] as
<子查询>
[with check option]
中括号里面的语句是可缺省的,需要说明以下两点:
-
[<列名>...]中括号里面为视图的属性名,如果缺省,则默认为该视图为子查询结果中的属性名。
-
with check option则指明当对视图进行insert、update、delete时,要检查进行insert、update、delete的元组是否满足视图定义中子查询中定义的条件表达式,就是确保更新以后的视图与一开始定义的视图保持一致。
一个简单的例子:
-- 从学成成绩表中创建每个学生的平均成绩视图
CREATE VIEW avgGrade(sno,avg_grade) as
select sno,AVG(grade) from E
group by sno
with check option
视图的查询
视图就相当于一个虚拟表,所有对基本表的查询语句,对视图也同样适用。例如查询刚才创建的视图:
select * from avgGrade
视图的更新
这里提到的视图更新包括UPDATE,DELETE,INSERT三种操作,基本的语句也是与表的更新操作相同,但因视图不保存数据,对视图的更新最终要反映到对基本表的更新上,而有时,视图定义的映射是不可逆的。所以视图的更新是一个较为复杂的问题,我们放到最后单独分析。
视图的撤销
drop view <视图名> [cascade];
因为视图可能是另一个视图导出的,cascade 将删除由它导出的所有视图。
视图是否可更新?
答案是视情况而定。
通常,视图是可更新的(即可进行UPDATE,DELETE,INSERT)。对于由单一表的子集构成的视图,即如果视图是从单个基本表使用选择、投影操作导出的,并且包含了基本表的主键,则可以更新。并且更新一个视图将更新其基表。
但是,并非所有视图都是可更新的。基本可以说,如果不能正确得确定被更新的基数据,则不允许更新(包括插入和删除)。这实际上意味着,如果视图定义中有情况操作,则不能进行更新:
- 分组(group by 和having)
- 联结
- 子查询
- 并
unique
- 聚集函数(Min(),Count(),Sum()等)
distinct
- 导出计算列
- 如果视图是由单个表的列构成的,但并没有包括主键,则不能更新
由此可见,我们之前创建的学生平均成绩视图因为使用了分组和聚集函数,所以是不能更新的。其实这种视图更新限制的机制也很好理解,如果视图更新平均成绩,那这个平均成绩要怎么反映到基表中呢?
需要强调的是,一般应将视图用于检索不用于更新。
下面简单说明更新视图的一些细节问题。
-
insert操作时,因为视图不一定包含基本表中的所有列,所以,最终插入到基本表时,没有涉及到的列会被设为默认值。这里也间接说明了为什么没有主键的视图不能进行更新了。
-
如果创建视图时加上了with check option,则使用update、insert、delete时会在where部分加上子查询的条件表达式。不满足条件则报错。这样可以确保更新以后的视图与一开始定义的视图保持一致。如果不添加这句话,则对视图进行insert、update、delete时,可以插入任何不违反基表约束的记录。
例如:--创建学号为1102同学的不同学期的成绩视图 create view Test as select sno,semester,grade from E where sno=1102 with check option update Test set grade=90 where semester='202001' --对视图进行update操作 --相当于 update Test set grade=90 where semester='202001' and sno=1102 --sno=1102被加到where部分
这也说明对于没有where子句的视图,使用with check option是多余的。