• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 更新和插入视图

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

    为了使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。还有某些其他构造会使视图不可更新。更具体地说,如果视图包含以下任何内容,则该视图不可更新:

    • 聚集函数或窗函数(SUM()MIN()MAX()COUNT(),等等)
    • DISTINCT
    • GROUP BY
    • HAVING
    • UNION要么UNION ALL
    • 选择列表中的子查询

      在选择列表非依赖的子查询失败INSERT,但都还好的UPDATEDELETE。对于选择列表中的从属子查询,不允许使用数据更改语句。

    • 某些联接(请参阅本节后面的其他联接讨论)
    • FROM子句中引用不可更新的视图
    • 子查询的WHERE子句是指表在FROM条款
    • 仅引用文字值(在这种情况下,没有要更新的基础表)
    • ALGORITHM = TEMPTABLE(使用临时表总是使视图不可更新)
    • 到基台的任一列的多个引用(为失败INSERT,还好为UPDATEDELETE

    视图中生成的列被认为是可更新的,因为可以对其进行分配。但是,如果显式更新了此类列,则唯一允许的值为DEFAULT。有关生成的列的信息,请参见“创建表和生成的列”。

    假设可以使用MERGE算法处理多表视图,则有时可能是可更新的。为此,视图必须使用内部联接(而不是外部联接或UNION)。另外,视图定义中的单个表只能更新,因此该SET子句必须仅命名视图中表之一中的列。UNION ALL尽管从理论上讲它们是可以更新的,但不允许使用这些视图。

    关于可插入性(可通过INSERT语句更新),如果可更新视图还满足视图列的以下其他要求,则可插入该视图:

    • 视图列名称不得重复。
    • 该视图必须包含基本表中所有没有默认值的列。
    • 视图列必须是简单的列引用。它们不能是以下表达式:

      3.14159
      col1 + 3
      UPPER(col2)
      col3 / col4
      (subquery)
      

    MySQL会设置一个标志,称为视图可更新性标志CREATE VIEWYES如果UPDATE和和DELETE(以及类似的操作)对该视图合法,则将该标志设置为(true)。否则,该标志设置为NO(false)。表中的IS_UPDATABLEINFORMATION_SCHEMA.VIEWS显示此标志的状态。这意味着服务器始终知道视图是否可更新。

    如果视图是不可更新的,这样的语句UPDATEDELETE以及INSERT是非法的,将被拒绝。(即使视图是可更新的,也可能无法插入其中,如本节其他地方所述。)

    视图的可更新性可能受updatable_views_with_limit系统变量的值影响。请参见“服务器系统变量”。

    对于以下讨论,假设存在这些表和视图:

    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;
      
    • DELETEDELETE语句中要从中删除的一个或多个表必须是合并视图。不允许加入视图(与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(),因为将默认值插入不属于该视图的列中的副作用应该是不可见的。