### 25.5.3 可更新和可插入的视图

[](<>)[](<>)[](<>)[](<>)

某些视图是可更新的，并且对它们的引用可用于指定要在数据更改语句中更新的表。也就是说，您可以在语句中使用它们，例如[`更新`](update.html),[`删除`](delete.html)， 要么[`插入`](insert.html)更新基础表的内容。派生表和公用表表达式也可以在多表中指定[`更新`](update.html)和[`删除`](delete.html)语句，但只能用于读取数据以指定要更新或删除的行。通常，视图引用必须是可更新的，这意味着它们可以被合并而不是具体化。复合视图有更复杂的规则。

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

-   聚合函数或窗口函数 ([`和（）`](aggregate-functions.html#function_sum),[`最小（）`](aggregate-functions.html#function_min),[`最大限度（）`](aggregate-functions.html#function_max),[`数数（）`](aggregate-functions.html#function_count), 等等)

-   `清楚的`

-   `通过...分组`

-   `拥有`

-   [`联盟`](union.html)要么[`联合所有`](union.html)

-   选择列表中的子查询

    选择列表中的非相关子查询失败[`插入`](insert.html), 但对[`更新`](update.html),[`删除`](delete.html).对于选择列表中的依赖子查询，不允许使用数据更改语句。

-   某些联接（请参阅本节后面的附加联接讨论）

-   对不可更新视图的引用`从`条款

-   中的子查询`在哪里`引用表中的表的子句`从`条款

-   仅指文字值（在这种情况下，没有要更新的基础表）

-   `算法 = 可取的`（使用临时表总是使视图不可更新）

-   对基表的任何列的多次引用（失败[`插入`](insert.html), 好吧[`更新`](update.html),[`删除`](delete.html))

[](<>)

视图中生成的列被认为是可更新的，因为它可以分配给它。但是，如果这样的列被显式更新，则唯一允许的值是`默认`.有关生成的列的信息，请参阅[第 13.1.20.8 节，“创建表和生成的列”](create-table-generated-columns.html).

假设可以使用`合并`算法。为此，视图必须使用内连接（不是外连接或[`联盟`](union.html)）。此外，视图定义中只能更新单个表，因此`放`子句必须仅命名视图中一张表中的列。使用的视图[`联合所有`](union.html)即使理论上它们可能是可更新的，也是不允许的。

关于可插入性（可更新[`插入`](insert.html)语句），如果可更新视图也满足视图列的这些附加要求，则它是可插入的：

-   不能有重复的视图列名称。

-   视图必须包含基表中没有默认值的所有列。

-   视图列必须是简单的列引用。它们不能是表达式，例如：

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

    MySQL 设置一个标志，称为视图可更新标志，在[`创建视图`](create-view.html)时间。标志设置为`是的`（真）如果[`更新`](update.html)和[`删除`](delete.html)（和类似的操作）对于视图是合法的。否则，标志设置为`不`（错误的）。这`IS_UPDATABLE`列中的[`INFORMATION_SCHEMA.VIEWS`](information-schema-views-table.html)表显示此标志的状态。这意味着服务器始终知道视图是否可更新。

    如果视图不可更新，则声明如下[`更新`](update.html),[`删除`](delete.html)， 和[`插入`](insert.html)是非法的并被拒绝。（即使视图是可更新的，也可能无法插入其中，如本节其他地方所述。）

    视图的可更新性可能会受到[`update_views_with_limit`](server-system-variables.html#sysvar_updatable_views_with_limit)系统变量。看[第 5.1.8 节，“服务器系统变量”](server-system-variables.html).

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


```
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.html),[`更新`](update.html)， 和[`删除`](delete.html)允许的语句如下：

-   [`插入`](insert.html): 插入表[`插入`](insert.html)语句可能是合并的视图引用。如果视图是连接视图，则视图的所有组件都必须是可更新的（不是物化的）。对于多表可更新视图，[`插入`](insert.html)如果它插入到单个表中，则可以工作。

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

    ```
    INSERT INTO vjoin (c) VALUES (1);
    ```

    本声明有效；视图不包含物化组件：

    ```
    INSERT INTO vup (c) VALUES (1);
    ```

-   [`更新`](update.html)：要在一个或多个表中更新的表[`更新`](update.html)语句可能是合并的视图引用。如果视图是连接视图，则视图的至少一个组件必须是可更新的（这不同于[`插入`](insert.html)）。

    在多表中[`更新`](update.html)语句，该语句的更新表引用必须是基表或可更新视图引用。未更新的表引用可能是物化视图或派生表。

    本声明有效；柱子`c`来自连接视图的可更新部分：

    ```
    UPDATE vjoin SET c=c+1;
    ```

    该声明无效；柱子`x`来自不可更新的部分：

    ```
    UPDATE vjoin SET x=x+1;
    ```

    本声明有效；多表的更新表引用[`更新`](update.html)是一个可更新的视图（`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.html)：要从一个或多个表中删除的表[`删除`](delete.html)声明必须是合并视图。不允许加入视图（这不同于[`插入`](insert.html)和[`更新`](update.html)）。

    此语句无效，因为该视图是一个连接视图：

    ```
    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;
```

如果一个表包含一个`自动递增`列，插入到表上不包括`自动递增`列的值不会改变[`LAST_INSERT_ID()`](information-functions.html#function_last-insert-id)，因为将默认值插入不属于视图的列的副作用不应该是可见的。
