视图(View) 是一种虚拟的表,它的内容由查询定义,但不存储实际的数据。视图是从一个或多个基本表(或其他视图)生成的。
特点:
- 虚拟性:视图不包含数据本身,仅保存了一个查询,这个查询在每次访问视图时动态地执行。
- 动态性:视图显示的数据是从基本表中实时检索出来的。因此,当基本表的数据发生变化时,视图显示的数据也会随之改变。
- 安全性:通过视图,可以限制用户访问基本表的特定数据,从而增强了数据库的安全性。
- 简便性:视图可以简化复杂的SQL操作。用户可以通过查询视图,而不必直接查询复杂的基本表。
- 逻辑独立性:用户可以使用视图而不必关心数据在基本表中是如何存储的。
创建视图的目的是从一个或多个基本表(或其他视图)中提取数据,形成一个虚拟表。视图不存储实际的数据,而是保存了一个SQL查询作为其定义。这样,每次查询视图时,都会运行该查询以生成数据。
创建视图的基本语法如下:
CREATE VIEW<视图名> [(<列名>[,列名>]... )]
AS<SELECT语句>
[WITH CHECK OPTION];
- <视图名>:要创建的视图的名称。
- <列名1>, <列名2>, ...:视图中的列名称,这是可选的。如果省略,则视图的列名称将是SELECT语句中指定的列名称。
- :定义视图的查询。
- WITH CHECK OPTION:这是一个可选的声明,用于确保所有视图修改都符合视图的SELECT语句的条件。
(1) 行列子集视图
若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了码,则称这类视图为行列子集视图。
建立计科 0701 班学生的视图,并要求在进行修改和插入操作时仍需保证该视图中只有计算机系的学生。
CREATE VIEW CS_S
AS
SELECT Sno, Sname, Sage
FROM S
WHERE Sclass ='CS0701'
WITH CHECK OPTION;
(2)由视图导出的视图
在已有视图的基础上创建新的视图。例如,基于CS_S视图,创建一个新视图,包含选修03号课程的学生信息:
CREATE VIEW CS_S1(Sno, Sname, Grade) AS
SELECT S.Sno, Sname, Grade
FROM CS_S, SC
WHERE CS_S.Sno = SC.Sno AND SC.Cno = '03';
(3) 带虚拟列的视图
定义视图时可以根据应用的需要,设置一些派生属性列。这些派生属性列由于在基本表中并不实际存在,因此也称它们为虚拟列。带虚拟列的视图也称为带表达式的视图。
定义一个反映学生出生年份的视图。
CREATE VIEW BS(Sno,Sname,Sbirth)
AS
SELECT Sno, Sname,2011 - Sage
FROM S:
BS 视图是一个带表达式的视图。视图中的出生年份值是通过计算得到的。
(4) 带有集函数的视图
还可以用带有集函数和 GROUP BY 子句的查询来定义视图,这种视图称为分组视图。
将学生的学号及他们的平均成绩定义为一个视图。
CREATE VIEW S_G(Sno, Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
2.删除视图
格式:
DROP VIEW <视图名>;
视图删除后视图的定义将从数据字典中删除,但由该视图导出的其他视图定义仍在数据字典中,但已经失效,不能继续使用,应该将它们一一删除。
DROP VIEW CS_S1;
DROP VIEW CS_S;
二.查询视图
查询视图时,可以像查询基本表一样操作。以下是视图查询的详细说明:
视图查询的基本操作例如,查询计算机科学专业 0701 班年龄小于 20 岁的学生:
SELECT Sno,Sage FROM CS_S WHERE Sage < 20;
视图查询的内部机制
- 有效性检查:数据库管理系统(DBMS)首先检查所查询的表或视图是否存在。
- 视图消解:DBMS 从数据字典中获取视图定义,并将视图定义中的子查询与用户查询结合转换为针对基本表的查询。
例如,上述视图查询实际转换为针对基本表的查询:
SELECT Sno Sage FROM S WHERE Sclass ='CS0701' AND Sage < 20;
查询转换的注意事项
在大多数情况下,视图查询可以直接转换。但在某些情况下,直接转换可能不可行或会导致问题。
- 带集函数的视图查询:例如,查询平均成绩在 90 分以上的学生学号和平均成绩:
SELECT *
FROM S_G
WHERE Gavg >= 90;
将上面查询语句与子查询结合,形成下列查询语句。
SELECT Sno,AVG( Grade)
FROM SC
WHERE AVG(Grade)> = 90
GROUP BY Sno;
前面讲过分组后 WHERE 子句中不能用集函数作为条件表达式,因此执行此修正后的查询将会出现语法错误。正确的查询语句应该是:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG( Grade)> = 90;
视图查询的限制
- 行列子集视图:大多数数据库系统能够正确转换行列子集视图的查询。
- 非行列子集视图:对于非行列子集的视图,转换可能不总是可行。在这种情况下,建议直接对基本表进行查询。
由于视图不实际存储数据,对视图的更新实际上是对其基本表数据的更新。使用 WITH CHECK OPTION 可以确保视图更新操作符合视图定义的约束。
1.插入视图数据向视图中插入数据会转换为向基本表中插入数据。例如,向计科 0701 班学生视图 CS_S 中插入一个新的学生记录:
INSERT INTO CS_S
VALUES('2007111003','王欢', 20);
此操作转换为对基本表的插入:
INSERT INTO S(Sno, Sname, Sage, Sclass)
VALUES('2007111003', '王欢', 20, 'CS0701');
系统会自动处理与视图定义相关的其他属性(如在这里自动添加班级名称 'CS0701')。
2.删除视图数据从视图中删除数据转换为从基本表中删除相应的数据。例如,删除计科 0701 班学生视图 CS_S 中学号为 2007111003 的记录:
DELETE FROM CS_S
WHERE Sno = '2007111003';
转换为对基本表的删除操作:
DELETE FROM S
WHERE Sno = '2007111003' AND Sclass = 'CS0701';
3.修改视图数据
修改视图数据转换为对基本表的更新。例如,将计科 0701 班学生视图 CS_S 中学号为 2007111001 的学生的姓名改为“张强”:
UPDATE CS_S
SET Sname = '张强'
WHERE Sno = '2007111001';
转换为对基本表的更新:
UPDATE S
SET Sname = '张强'
WHERE Sno = '2007111001' AND Sclass = 'CS0701';
可更新性的限制
不是所有视图都可更新。特别是那些包含集函数、分组或从多个基本表派生的视图,其更新可能不会有唯一明确的基本表更新对应。如视图 S_G,其包含了平均成绩,这是一个通过分组和聚合计算得出的结果,无法直接映射到基本表的特定记录上进行更新。
UPDATE S_G
SET Gavg = 90
WHERE Sno='2007111001'; /*这是不行的*/
因此,对于非行列子集视图的更新,需要考虑其可更新性以及如何有效地映射到基本表的更新操作。