一些视图是可更新的,对它们的引用可以用来指定要更新的表,用于数据更改语句。也就是说,您可以在语句中使用它们,例如 UPDATE
、DELETE
或 INSERT
来更新基础表的内容。派生表和公用表表达式也可以在多表 UPDATE
和 DELETE
语句中指定,但只能用于读取数据来指定要更新或删除的行。通常,视图引用必须是可更新的,这意味着它们可以合并,而不是物化。组合视图具有更复杂的规则。
为了使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。还有一些其他结构使视图不可更新。更准确地说,如果视图包含以下任何内容,则它不可更新
视图中的生成列被认为是可更新的,因为可以为它赋值。但是,如果显式更新这样的列,则唯一允许的值是 DEFAULT
。有关生成列的信息,请参阅 第 15.1.20.8 节,“CREATE TABLE 和生成列”。
有时,多表视图可以是可更新的,假设它可以使用 MERGE
算法进行处理。为此,视图必须使用内联接(而不是外联接或 UNION
)。此外,视图定义中只有一个表可以更新,因此 SET
子句必须仅命名视图中一个表的列。即使在理论上它们可能是可更新的,也不允许使用 UNION ALL
的视图。
关于可插入性(使用 INSERT
语句可更新),如果可更新视图也满足视图列的以下附加要求,则它是可插入的
视图列名不能重复。
视图必须包含基表中所有没有默认值的列。
视图列必须是简单的列引用。它们不能是表达式,例如以下这些
3.14159 col1 + 3 UPPER(col2) col3 / col4 (subquery)
MySQL 在 CREATE VIEW
时设置一个标志,称为视图可更新性标志。如果 UPDATE
和 DELETE
(以及类似操作)对视图来说是合法的,则该标志被设置为 YES
(真)。否则,该标志被设置为 NO
(假)。Information Schema VIEWS
表中的 IS_UPDATABLE
列显示此标志的状态。这意味着服务器始终知道视图是否可更新。
如果视图不可更新,则诸如 UPDATE
、DELETE
和 INSERT
的语句是违法的,会被拒绝。(即使视图是可更新的,也可能无法插入,如本节其他地方所述。)
视图的可更新性可能会受到 updatable_views_with_limit
系统变量的值影响。请参阅 第 7.1.8 节,“服务器系统变量”。
对于以下讨论,假设这些表和视图存在
CREATE TABLE t1 (x INTEGER);
CREATE TABLE t2 (c INTEGER);
CREATE VIEW vmat AS SELECT SUM(x) AS s FROM t1;
CREATE VIEW vup AS SELECT * FROM t2;
CREATE VIEW vjoin AS SELECT * FROM vmat JOIN vup ON vmat.s=vup.c;
INSERT
、UPDATE
和 DELETE
语句允许如下操作
INSERT
:INSERT
语句的插入表可以是合并的视图引用。如果视图是联接视图,则视图的所有组件都必须是可更新的(不物化)。对于多表可更新视图,如果将数据插入到单个表中,则INSERT
可以工作。此语句无效,因为联接视图的一个组件不可更新
INSERT INTO vjoin (c) VALUES (1);
此语句有效;视图不包含任何物化的组件
INSERT INTO vup (c) VALUES (1);
UPDATE
:UPDATE
语句中要更新的表或多个表可以是合并的视图引用。如果视图是联接视图,则视图的至少一个组件必须是可更新的(这与INSERT
不同)。在多表
UPDATE
语句中,语句的更新表引用必须是基表或可更新视图引用。未更新的表引用可以是物化视图或派生表。此语句有效;列
c
来自联接视图的可更新部分UPDATE vjoin SET c=c+1;
此语句无效;列
x
来自不可更新的部分UPDATE vjoin SET x=x+1;
此语句有效;多表
UPDATE
的更新表引用是可更新视图 (vup
)UPDATE vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ... SET c=c+1;
此语句无效;它尝试更新物化的派生表
UPDATE vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ... SET s=s+1;
DELETE
:DELETE
语句中要从中删除的表或多个表必须是合并的视图。不允许联接视图(这与INSERT
和UPDATE
不同)。此语句无效,因为视图是联接视图
DELETE vjoin WHERE ...;
此语句有效,因为视图是合并的(可更新的)视图
DELETE vup WHERE ...;
此语句有效,因为它从合并的(可更新的)视图中删除数据
DELETE vup FROM vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ...;
以下是更多讨论和示例。
本节之前的讨论指出,如果视图中并非所有列都是简单列引用(例如,如果视图包含表达式或复合表达式列),则该视图不可插入。尽管此类视图不可插入,但如果仅更新非表达式列,则它可以更新。考虑此视图
CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
此视图不可插入,因为 col2
是一个表达式。但是,如果更新不尝试更新 col2
,则该视图是可更新的。此更新是允许的
UPDATE v SET col1 = 0;
此更新是不允许的,因为它试图更新表达式列
UPDATE v SET col2 = 0;
如果表包含一个 AUTO_INCREMENT
列,则在不包含 AUTO_INCREMENT
列的表上的可插入视图中插入数据不会更改 LAST_INSERT_ID()
的值,因为将默认值插入到非视图部分的列中的副作用不应可见。