文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (美国信纸) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  可更新和可插入视图

27.6.3 可更新和可插入视图

一些视图是可更新的,对它们的引用可用于指定要更新的表,用于数据更改语句。也就是说,您可以在诸如 UPDATEDELETEINSERT 之类的语句中使用它们来更新基础表的 内容。派生表和公用表表达式也可以在多表 UPDATEDELETE 语句中指定,但只能用于读取数据以指定要更新或删除的行。 通常,视图引用必须是可更新的,这意味着它们可以合并而不必物化。组合视图具有更复杂的规则。

对于可更新的视图,视图中的行与基础表中的行之间必须是一对一的关系。还有一些其他结构使视图不可更新。 更确切地说,如果视图包含以下任何内容,则它不可更新:

  • 聚合函数或窗口函数 (SUM()MIN()MAX()COUNT() 等)

  • DISTINCT

  • GROUP BY

  • HAVING

  • UNIONUNION ALL

  • select 列表中的子查询

    select 列表中的非依赖子查询对于 INSERT 失败,但对于 UPDATEDELETE 是可以的。对于 select 列表中的依赖子查询,不允许任何数据更改语句。

  • 某些连接(有关本节后面的其他连接讨论)

  • FROM 子句中引用不可更新的视图

  • WHERE 子句中的子查询引用 FROM 子句中的表

  • 仅引用字面量值(在这种情况下,没有要更新的基础表)

  • ALGORITHM = TEMPTABLE(使用临时表始终使视图不可更新)

  • 对任何基本表的任何列的多次引用(对于 INSERT 失败,但对于 UPDATEDELETE 是可以的)

视图中的生成列被认为是可更新的,因为可以对其赋值。但是,如果显式更新这样的列,则唯一允许的值是 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 时设置一个标志,称为视图可更新标志。如果 UPDATEDELETE(以及类似操作)对于视图是合法的,则该标志被设置为 YES(真)。否则,该标志被设置为 NO(假)。信息模式 VIEWS 表中的 IS_UPDATABLE 列显示此标志的状态。这意味着服务器始终知道视图是否可更新。

如果视图不可更新,则诸如 UPDATEDELETEINSERT 之类的语句是非法的,将被拒绝。(即使视图是可更新的,也可能无法插入到其中,如本节其他地方所述。)

视图的可更新性可能会受到 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;

INSERTUPDATEDELETE 语句允许如下

  • INSERTINSERT 语句的插入表可以是合并的视图引用。如果视图是连接视图,则视图的所有组件都必须是可更新的(不能物化)。对于多表可更新视图,如果插入到单个表中,则 INSERT 可以正常工作。

    此语句无效,因为连接视图的一个组件不可更新

    INSERT INTO vjoin (c) VALUES (1);

    此语句有效;视图不包含物化组件

    INSERT INTO vup (c) VALUES (1);
  • UPDATEUPDATE 语句中要更新的表可以是合并的视图引用。如果视图是连接视图,则视图的至少一个组件必须是可更新的(这与 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 语句中要删除的表必须是合并视图。不允许使用联接视图(这与 INSERTUPDATE 不同)。

    此语句无效,因为视图是联接视图。

    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() 的值,因为将默认值插入到不在视图中的列的副作用不应可见。