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
。
视图定义在创建时是“冻结的”,并且不受底层表定义的后续更改的影响。例如,如果视图定义为在表上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
子句的语句从视图中进行选择,则未定义哪个限制适用。同样的原则也适用于 SELECT
关键字之后的 ALL
、DISTINCT
或 SQL_SMALL_RESULT
等选项,以及 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
值应为指定为 '
、user_name
'@'host_name
'CURRENT_USER
或 CURRENT_USER()
的 MySQL 帐户。允许的 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
值。如果视图定义包含 CURRENT_USER
的 DEFINER
值,这也将影响在此类例程中定义的视图。
MySQL 如下检查视图权限:
在视图定义时,视图创建者必须具有使用视图访问的顶层对象所需的权限。例如,如果视图定义引用表列,则创建者必须对定义的选择列表中的每一列都具有一些权限,并且对定义中其他位置使用的每一列都具有
SELECT
权限。如果定义引用存储函数,则只能检查调用该函数所需的权限。函数调用时所需的权限只能在函数执行时进行检查:对于不同的调用,可能会采用函数内的不同执行路径。引用视图后,将根据
SQL SECURITY
特性是DEFINER
还是INVOKER
,分别针对视图DEFINER
帐户或调用者持有的权限检查对视图访问的对象的权限。如果对视图的引用导致执行存储函数,则对函数内执行的语句的权限检查取决于函数
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()
执行时,需要检查在 f()
内执行语句所需的权限。这可能意味着需要 p1()
或 p2()
的权限,具体取决于 f()
内的执行路径。必须在运行时检查这些权限,并且必须拥有这些权限的用户由视图 v
和函数 f()
的 SQL SECURITY
值确定。
视图的 DEFINER
和 SQL SECURITY
子句是对标准 SQL 的扩展。在标准 SQL 中,视图是使用 SQL SECURITY DEFINER
的规则处理的。该标准规定,视图的定义者(与视图的模式的所有者相同)将获得视图上的适用权限(例如 SELECT
),并且可以授予这些权限。MySQL 没有模式“所有者”的概念,因此 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
子句为真的行除外。
在可更新视图的 WITH CHECK OPTION
子句中,当根据另一个视图定义视图时,LOCAL
和 CASCADED
关键字确定检查测试的范围。LOCAL
关键字将 CHECK OPTION
仅限于正在定义的视图。CASCADED
会导致同时评估对基础视图的检查。如果未指定任何一个关键字,则默认为 CASCADED
。
有关可更新视图和 WITH CHECK OPTION
子句的更多信息,请参阅 第 27.5.3 节“可更新和可插入视图”,以及 第 27.5.4 节“视图 WITH CHECK OPTION 子句”。