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.10 节“视图限制”。
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.7 节“存储对象访问控制” 中所述。
引用视图时,权限检查将在本节稍后描述。
视图属于数据库。默认情况下,新视图在默认数据库中创建。要在给定数据库中显式创建视图,请使用 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.7 节“存储对象访问控制” 中所述。另请参阅该部分以获取有关视图安全性的其他信息。
如果省略 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 列表中的每一列都具有一些权限,并且对定义中其他地方使用的每一列都具有
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.6.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.6.3 节“可更新和可插入视图”,以及 第 27.6.4 节“视图 WITH CHECK OPTION 子句”。