## 1.11 视图

前几个小节介绍了SQL的增删改查功能，其中查询是SQL最核心的功能。其实，使用SQL语言来书写查询语句可以类比为使用C语言来编写程序。在编写程序时，为了使程序的整体逻辑更加清晰和提升程序开发效率，程序员会使用函数（Function）来实现程序的模块化设计。通常，重复使用的计算功能会被封装成一个函数，然后在程序的其他部分反复被调用。同样地，SQL也提供了类似函数的功能，它将重复使用的查询结果封装成视图（View），然后在SQL的其他部分直接调用视图。

视图是从一个或几个基本表（或视图）导出的表。但是，它是一张虚表。数据库中只存放视图的定义，而不存放视图对应的数据。当使用视图做查询时，数据库管理系统首先执行视图的SQL查询语句，获得视图的结果之后，在视图的结果之上再执行查询。这和函数的使用是一样的，当调用函数时，程序需要重新执行一遍函数。值得注意的是，一旦基本表中的数据发生变化后，从视图中查询出的数据也将随之改变。

视图一经定义，就可以和基本表一样被查询、被更新、被删除。但是，对视图的更新（增、删、改）操作有一定的限制。


### 1.11.1  视图的创建

SQL语言用CREATE VIEW命令来创建视图，其基本格式如下：

```SQL
CREATE VIEW <视图名> [（<列名1> [, <列名2>] ...）] 
AS <子查询>
[WITH CHECK OPTION];
```

其中子查询是任意的SELECT查询语句；WITH CHECK OPTION表示对视图进行增、删、改操作时要进行校验，保证更新的元组满足视图的定义。

```SQL
[例1.40] 创建男生信息的视图。
CREATE VIEW M_Student 
AS
SELECT Sno, Sname, Age,Dept
FROM Student
WHERE Gender = '男';
```

本例省略了视图M_Student的属性列名，其隐含意思是视图的属性列由子查询中SELECT子句的四个列名组成。关系数据库管理系统执行CREATE VIEW语句时只是把视图的定义存入数据字典，并不执行其中的SELECT语句。只有在对视图查询时，才按视图的定义从基本表中将数据查出。

视图不仅可以建立在一个或者多个基本表上，也可以建立在一个或多个已定义的视图上，或建立在基本表与视图上。

### 1.11.2 视图的删除

SQL语言用DROP VIEW命令来删除视图，其基本格式为：

```SQL
DROP VIEW <视图名> [CASCADE] ;
```
删除视图其实是将视图的定义从数据字典中删除。如果视图之上还建立了其他视图，那么删除时则需要使用关键词CASCADE，表示将视图和由它导出的所有视图一起删除。

当基本表被删除后，基于基本表创建的所有视图都无法使用，但视图的定义仍存在于数据字典中，此时就需要使用DROP VIEW语句来删除视图。

```SQL
[例1.41] 删除视图M_Student。
DROP VIEW M_Student CASCADE;
```

### 1.11.3  视图的查询

视图创建之后，就可以对视图进行查询，其基本格式与基本表的查询格式相同。

```SQL
[例1.42] 查询年龄小于19岁的男生学号和姓名。
SELECT Sno,Sname
FROM M_Student
WHERE Age < 19;
```

该语句的执行过程是：首先进行有效性检查，检查查询中涉及的视图是否存在。如果存在，则从数据字典中取出视图的定义，把视图定义中的子查询和此查询结合起来，转换成等价的对基本表的新查询，然后执行新查询。

例1.42转换之后的查询语句为：
```SQL
SELECT Sno,Sname<br>
FROM Student<br>
WHERE Gender = '男' AND Age < 19;
```

### 1.11.4  视图的更新

更新视图其实是通过视图来增、删、改数据。由于视图是一张虚表，不存储任何数据，因此对视图的更新最终是转换成对基本表的增、删、改。如果定义视图时加上了WITH CHECK OPTION子句，那么执行更新视图SQL时需要检查更新数据是否满足视图的定义，如果不满足定义则不执行操作。

```SQL
[例1.43] 将男生视图M_Student中学号为2022123的学生姓名改为宇轩。
UPDATE M_Student
SET Sname = '宇轩' 
WHERE Sno = '2022123';
转换为对基本表更新的SQL为：
UPDATE Student
SET Sname = '宇轩' 
WHERE Sno = '2022123' AND Gender = '男';
```
```SQL
[例1.44] 向男生视图M_Student中插入一个新的学生信息（学号：2022013，姓名：宇轩，年龄：20，系：计算机）。
INSERT
INTO M_Student 
VALUES('2022013','宇轩',20,'计算机');
转换为对基本表的插入：
INSERT
INTO M_Student(Sno,Sname,Gender, Age, Dept)
VALUES('2022013','宇轩','男', 20, '计算机');
```
```SQL
[例1.45] 删除男生视图M\_Student中学号为2022013的学生信息。
DELETE
FROM M_Student
WHERE Sno = '2022013';
转换为对基本表的删除：
DELETE
FROM M_Student
WHERE Sno = '2022013' AND Gender = '男';
```

在关系数据库中，不是所有的视图都能被更新。如果对某个视图的增、删、改操作不能转换成对应基本表的增、删、改，那么该视图就不能被更新。

视图除了使查询语句SQL的逻辑更加清晰，简化用户的SQL编写之外，还能实现用户的权限访问功能。

### 练习题

**1**. 以下对视图的说法正确的是：

 <ol type="A">
 <li>视图的使用可以提升查询的性能</li>
 <li>视图是虚拟的，因此不能在视图上实施数据的增删改</li>
 <li>视图之上不能构建新的视图</li>
 <li>视图的使用可以增加软件开发的效率</li>
 </ol>

[**上一页<<**](chapter1.10-R.md) | [**>>下一页**](chapter1.12-D.md)
