CREATE
[OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
[DEFINER = user]
[SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
该 CREATE VIEW
语句创建一个新的视图,或者如果给出了 OR REPLACE
子句,则替换现有的视图。如果视图不存在, CREATE OR REPLACE VIEW
与 CREATE VIEW
相同。如果视图已经存在, CREATE OR REPLACE VIEW
将其替换。
有关视图使用限制的信息,请参阅 第 27.9 节,“视图限制”。
该 select_statement
是一个 SELECT
语句,提供了视图的定义。(从视图中选择实际上是使用 SELECT
语句。)该 select_statement
可以从基本表或其他视图中选择。该 SELECT
语句可以使用 VALUES
语句作为其源,或者可以被 TABLE
语句所取代,如同 CREATE TABLE ... SELECT
。
视图定义是在创建时“冻结”的,不受后续对基础表定义的更改的影响。例如,如果视图被定义为在表上选择所有列,后来添加到表中的新列不会成为视图的一部分,而从表中删除的列将在从视图中选择时导致错误。
该 ALGORITHM
子句影响 MySQL 如何处理视图。DEFINER
和 SQL SECURITY
子句指定了在视图调用时检查访问权限的安全上下文。WITH CHECK OPTION
子句可以用于约束对视图引用的表中的行的插入或更新。这些子句将在本节后面描述。
该 CREATE VIEW
语句需要对视图具有 CREATE VIEW
权限,并且对每个选择的列具有某些权限的 SELECT
语句。对于在 SELECT
语句中使用的其他列,您必须具有 SELECT
权限。如果存在 OR REPLACE
子句,您还必须具有视图的 DROP
权限。如果存在 DEFINER
子句,所需的权限取决于 user
值,如 第 27.6 节,“存储对象访问控制” 中所讨论的那样。
当视图被引用时,将按照本节后面所述的方式进行权限检查。
视图属于某个数据库。默认情况下,新视图将创建在默认数据库中。要在给定的数据库中显式创建视图,请使用 db_name.view_name
语法来限定视图名称与数据库名称:
CREATE VIEW test.v AS SELECT * FROM t;
在 SELECT
语句中的未限定表或视图名称也将相对于默认数据库进行解释。视图可以通过限定表或视图名称以数据库名称来引用其他数据库中的表或视图。
在数据库中,基本表和视图共享相同的命名空间,因此基本表和视图不能具有相同的名称。
由 SELECT
语句检索的列可以是简单的表列引用,也可以是使用函数、常量值、运算符等的表达式。
视图必须具有唯一的列名称,且不允许重复,就像基本表一样。默认情况下,SELECT
语句检索的列名称将用于视图列名称。要为视图列定义明确的名称,请指定可选的 column_list
子句作为逗号分隔的标识符列表。column_list
中的名称数量必须与 SELECT
语句检索的列数量相同。
视图可以从多种类型的 SELECT
语句创建。它可以引用基本表或其他视图。它可以使用连接、UNION
和子查询。该 SELECT
语句不需要引用任何表:
CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;
以下示例定义了一个视图,该视图从另一个表中选择两列,并计算出这些列的表达式:
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
视图定义受以下限制:
-
该
SELECT
语句不能引用系统变量或用户定义变量。 -
在存储程序中,该
SELECT
语句不能引用程序参数或局部变量。 -
该
SELECT
语句不能引用准备语句参数。 -
在定义中引用的任何表或视图必须存在。如果在创建视图后,定义中引用的表或视图被删除,使用视图将导致错误。要检查视图定义中的这种问题,请使用
CHECK TABLE
语句。 -
定义不能引用
TEMPORARY
表,您也不能创建TEMPORARY
视图。 -
您不能将触发器与视图关联。
-
别名列名在
SELECT
语句中的检查是针对最大列长度的 64 个字符(而不是别名长度的 256 个字符)。
ORDER BY
在视图定义中是允许的,但如果您使用带有自己的 ORDER BY
的语句从视图中选择,它将被忽略。
对于定义中的其他选项或子句,它们将被添加到引用视图的语句的选项或子句中,但效果未定义。例如,如果视图定义包括 LIMIT
子句,并且您使用带有自己的 LIMIT
子句的语句从视图中选择,那么哪个限制适用将是未定义的。同样的原则也适用于 ALL
、DISTINCT
或 SQL_SMALL_RESULT
等选项,它们跟随 SELECT
关键字,以及 INTO
、FOR UPDATE
、FOR SHARE
、LOCK IN SHARE MODE
和 PROCEDURE
等子句。
从视图中获得的结果可能会受到影响,如果您通过更改系统变量来更改查询处理环境:
mysql> CREATE VIEW v (mycol) AS SELECT 'abc';
Query OK, 0 rows affected (0.01 sec)
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT "mycol" FROM v;
+-------+
| mycol |
+-------+
| mycol |
+-------+
1 row in set (0.01 sec)
mysql> SET sql_mode = 'ANSI_QUOTES';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT "mycol" FROM v;
+-------+
| mycol |
+-------+
| abc |
+-------+
1 row in set (0.00 sec)
视图的 DEFINER
和 SQL SECURITY
子句确定了在执行引用视图的语句时用于检查访问权限的 MySQL 帐户。有效的 SQL SECURITY
特征值是 DEFINER
(默认)和 INVOKER
。这些指示需要的权限必须由定义或调用视图的用户持有。
如果存在 DEFINER
子句,user
值应该是一个指定为 '
的 MySQL 帐户,user_name
'@'host_name
'CURRENT_USER
或 CURRENT_USER()
。允许的 user
值取决于您持有的权限,如 第 27.6 节,“存储对象访问控制” 中所讨论的那样。还可以查看该节以获取关于视图安全的更多信息。
如果省略 DEFINER
子句,默认定义者是执行 CREATE VIEW
语句的用户。这与指定 DEFINER = CURRENT_USER
是相同的。
在视图定义中,CURRENT_USER
函数默认返回视图的 DEFINER
值。对于定义为 SQL SECURITY INVOKER
特征的视图,CURRENT_USER
返回视图的调用者帐户。关于视图中的用户审核,请参阅 第 8.2.23 节,“基于 SQL 的帐户活动审核”。
在定义为 SQL SECURITY DEFINER
特征的存储过程中,CURRENT_USER
返回过程的 DEFINER
值。这也影响了在该过程中定义的视图,如果视图定义包含 DEFINER
值为 CURRENT_USER
。
MySQL 按照以下方式检查视图权限:
-
在视图定义时,视图创建者必须拥有访问顶级对象的权限,例如,如果视图定义引用表列,创建者必须拥有选择列表中每列的某些权限,以及定义中使用的每列的
SELECT
权限。如果定义引用存储函数,只能检查函数调用的权限。在函数执行时可以检查执行路径中的权限:对于不同的调用,函数中的不同执行路径可能会被采取。 -
当视图被引用时,对视图访问的对象的权限将根据视图的
DEFINER
帐户或调用者来检查,具体取决于SQL SECURITY
特征是DEFINER
还是INVOKER
。 -
如果对视图的引用导致存储函数的执行,那么在函数中执行的语句的权限检查将取决于函数的
SQL SECURITY
特征是DEFINER
还是INVOKER
。如果安全特征是DEFINER
,函数将以DEFINER
帐户的权限运行。如果特征是INVOKER
,函数将以视图的SQL SECURITY
特征确定的权限运行。
示例:视图可能依赖于存储函数,而该函数可能会调用其他存储例程。例如,以下视图调用存储函数 f()
:
CREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);
假设 f()
包含以下语句:
IF name IS NULL then
CALL p1();
ELSE
CALL p2();
END IF;
在 f()
执行时,需要检查执行语句中的权限。这可能意味着需要 p1()
或 p2()
的权限,具体取决于 f()
中的执行路径。这些权限必须在运行时检查,而拥有这些权限的用户将根据视图 v
和函数 f()
的 SQL SECURITY
值来确定。
视图的 DEFINER
和 SQL SECURITY
子句是标准 SQL 的扩展。在标准 SQL 中,视图是使用 SQL SECURITY DEFINER
规则处理的。标准规定,视图的定义者(即视图 schema 的所有者)获得了视图的适用权限(例如,SELECT
),并且可以授予它们。MySQL 没有 schema “所有者”的概念,因此 MySQL 添加了一个子句来标识定义者。DEFINER
子句是一个扩展,旨在拥有标准所具有的内容,即永久记录谁定义了视图。这就是为什么默认 DEFINER
值是视图创建者的账户。
可选的 ALGORITHM
子句是 MySQL 对标准 SQL 的扩展。它影响 MySQL 如何处理视图。ALGORITHM
取三个值:MERGE
、TEMPTABLE
或 UNDEFINED
。有关更多信息,请参阅 第 27.5.2 节,“视图处理算法”,以及 第 10.2.2.4 节,“使用合并或物化优化派生表、视图引用和公共表表达式”。
一些视图是可更新的。这意味着,您可以在语句中使用它们,例如 UPDATE
、DELETE
或 INSERT
,以更新基础表的内容。要使视图可更新,必须在视图和基础表之间存在一对一的关系。此外,还有一些其他结构使视图不可更新。
视图中的生成列被认为是可更新的,因为可以分配给它。然而,如果显式更新了该列,则唯一允许的值是 DEFAULT
。有关生成列的信息,请参阅 第 15.1.20.8 节,“CREATE TABLE 和生成列”。
可以为可更新视图提供 WITH CHECK OPTION
子句,以防止插入或更新除 select_statement
中的 WHERE 子句为 true 的行以外的所有行。
在可更新视图的 WITH CHECK OPTION
子句中,LOCAL
和 CASCADED
关键字确定了视图定义时的检查测试范围。当视图定义为另一个视图时,这些关键字生效。LOCAL
关键字将 CHECK OPTION
仅限制在当前定义的视图上。CASCADED
导致对基础视图的检查也被评估。当没有给定关键字时,默认为 CASCADED
。
有关可更新视图和 WITH CHECK OPTION
子句的更多信息,请参阅 第 27.5.3 节,“可更新和可插入视图” 和 第 27.5.4 节,“视图 WITH CHECK OPTION 子句”。