4.2.4 视图更新

4.2.4 视图更新

尽管对查询而言,视图是一个有用的工具,但如果我们用它们来表达更新插入删除,它们可能带来严重的问题。困难在于,用视图表达的数据库修改必须被翻译为对数据库逻辑模型中实际关系的修改

向视图插入数据

更新一个表上的的视图的情况

假设我们此前所见的视图faculty被提供给一个职员。既然我们允许视图名出现在任何关系名可以出现的地方,该职员可以这样写出:

1
2
insert into faculty
values('30765','Green','Music');

这个插入必须表示为对instructor关系的插入,因为instructor是数据库系统用于构造视图faculty的实际关系。然而,为了把一个元组插入到instructor中,我们必须给出salary的值。存在两种合理的解决方法来处理该插入:

  1. 拒绝插入,并向用户返回一个错误信息。
  2. instructor关系插入元组('30765','Green', 'Music',null)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> insert into faculty
values('30765','Green','Music');
Query OK, 1 row affected (0.03 sec)

mysql> select * from instructor;
+-------+------------+------------+----------+
| ID | name | dept_name | salary |
+-------+------------+------------+----------+
| 10101 | Srinivasan | Comp. Sci. | 65000.00 |
| 12121 | Wu | Finance | 90000.00 |
| 15151 | Mozart | Music | 40000.00 |
| 22222 | Einstein | Physics | 95000.00 |
| 30765 | Green | Music | NULL |
| 32343 | El Said | History | 60000.00 |
| 33456 | Gold | Physics | 87000.00 |
| 45565 | Katz | Comp. Sci. | 75000.00 |
| 58583 | Califieri | History | 62000.00 |
| 76543 | Singh | Finance | 80000.00 |
| 76766 | Crick | Biology | 72000.00 |
| 83821 | Brandt | Comp. Sci. | 92000.00 |
| 98345 | Kim | Elec. Eng. | 80000.00 |
+-------+------------+------------+----------+
13 rows in set (0.04 sec)
1
| 30765 | Green      | Music      | NULL     |

更新多个表上的视图的情况

通过视图修改数据库的另一类问题发生在这样的视图上:

1
2
3
4
5
create view instructor_info
as
select ID, name,building
from instructor,department
where instructor.dept_name=department.dept_name;

这个视图列出了大学里每个教师的IDname建筑名
考虑如下通过该视图的插入:

1
2
insert into instructor_info
values('69987','White','Taylor');

假设没有标识为69987的教师,也没有位于Taylor大楼的系。那么向instructordepartment关系中插入元组的唯一可能的方法是:

  • instructor中插入元组('69987','White',null,null)
  • 并向department中插入元组('null','Taylor',null)

但是这个更新并没有产生出所需的结果,因为视图关系instructor_info中仍然不包含元组('69987','White','Taylor'),

1
2
3
mysql> insert into instructor_info
values('69987','White','Taylor');
1394 - Can not insert into join view 'university.instructor_info' without fields list

因此,通过利用空值来更新 instructordepartment关系以得到对instructor_info所需的更新是不可行的。

一般不允许对视图关系进行修改

由于如上所述的种种问题,除了一些有限的情况之外,一般不允许对视图关系进行修改
不同的数据库系统指定了不同的条件以允许更新视图关系;请参考数据库系统手册以获得详细信息。通过视图进行数据库修改的通用问题已经成为重要的研究课题,文献注解中引用了一些这方面的研究。

可更新的视图要满足的条件

一般说来,如果定义视图的查询对下列条件能满足我们称SQL视图是可更新的(updatable)(即视图上可以执行插入更新删除

  1. from子句中只有一个数据库关系。
  2. select子句中只包含关系的属性名,不包含任何表达式聚集distinct声明。
  3. 任何没有出现在select子句中的属性可以取空值;即这些属性上没有not null约束,也不构成主码的部分。
  4. 查询中不含有group byhaving子句。

实例 可更新的视图

在这些限制下,下面的视图上允许执行updateinsertdelete操作:

1
2
3
4
5
create view history_instructors
as
select *
from instructor
where dept_name ='History';

可更新的视图存在的问题

即便是在可更新的情况下,下面这些问题仍然存在。假设一个用户尝试向视图history_instructors中插入元组('25566','Brown','Biology',100000):

1
2
insert into history_instructors
values ('25566','Brown','Biology',100000);

这个元组可以被插入到instructor关系中,但是由于它不满足视图所要求的选择条件,它不会出现在视图history_instructors中。

1
2
3
mysql> insert into history_instructors
values ('25566','Brown','Biology',100000);
Query OK, 1 row affected (0.01 sec)
1
2
3
4
5
6
7
8
mysql> select * from history_instructors;
+-------+-----------+-----------+----------+
| ID | name | dept_name | salary |
+-------+-----------+-----------+----------+
| 32343 | El Said | History | 60000.00 |
| 58583 | Califieri | History | 62000.00 |
+-------+-----------+-----------+----------+
2 rows in set (0.03 sec)

拒绝向视图插入一条不满足视图的where子句条件的元组

在默认情况下,SQL允许执行上述更新。但是,可以通过在视图定义的末尾包含with check option子句的方式来定义视图。
这样,如果向视图中插入(insert)一条不满足视图的where子句条件的元组,数据库系统将拒绝插入操作。
类似地,如果更新的新值不满足where子句的条件,更新(update)也会被拒绝。

SQL:1999对视图更新的规则

SQL:1999对于何时可以在视图上执行插入、更新和删除有更复杂的规则集,该规则集允许通过类更大视图进行更新,但是这些规则过于复杂,我们就不在这里讨论了