13.1.21 CREATE VIEW 声明
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 VIEW相同。如果该视图确实存在,则创建或替换视图替换它。
有关视图使用限制的信息,请参见第 23.9 节“视图限制”。
select_statement
是提供视图定义的SELECT语句。 (实际上,使用SELECT语句从视图中进行选择。)select_statement
*可以从基本 table 或其他视图中进行选择。
视图定义在创建时被“冻结”,并且不受基础 table 定义的后续更改影响。例如,如果在 table 上将视图定义为SELECT *
,则以后添加到 table 中的新列将不成为视图的一部分,并且从 table 中删除的列在从视图中进行选择时将导致错误。
ALGORITHM
子句影响 MySQL 处理视图的方式。 DEFINER
和SQL SECURITY
子句指定在视图调用时检查访问特权时要使用的安全上下文。可以提供WITH CHECK OPTION
子句以约束对视图引用的 table 中行的插入或更新。这些子句将在本节后面介绍。
CREATE VIEW语句对视图具有CREATE VIEW特权,并且对SELECT语句选择的每一列都具有某些特权。对于SELECT语句中其他地方使用的列,您必须具有SELECT特权。如果存在OR REPLACE
子句,则您还必须具有该视图的DROP特权。如果存在DEFINER
子句,则所需的特权取决于* user
*值,如第 23.6 节“存储的对象访问控制”中所述。
引用视图后,将进行特权检查,如本节后面所述。
视图属于数据库。默认情况下,将在默认数据库中创建一个新视图。要在给定的数据库中显式创建视图,请使用* db_name.view_name
*语法用数据库名称限定视图名称:
CREATE VIEW test.v AS SELECT * FROM t;
SELECT语句中的不合格 table 名或视图名也会相对于默认数据库进行解释。视图可以通过用适当的数据库名称限定 table 或视图的名称来引用其他数据库中的 table 或视图。
在数据库中,基 table 和视图共享相同的名称空间,因此基 table 和视图不能具有相同的名称。
SELECT语句检索的列可以是对 table 列的简单引用,也可以是使用函数,常量值,运算符等的 table 达式。
视图必须具有唯一的列名,且不能重复,就像基 table 一样。默认情况下,由SELECT语句检索的列名称用于视图列名称。要为视图列定义显式名称,请指定可选的* column_list
*子句作为以逗号分隔的标识符的列 table。 * column_list
*中的名称数必须与SELECT语句检索到的列数相同。
可以使用多种SELECT语句创建视图。它可以引用基 table 或其他视图。它可以使用 joins,UNION和子查询。 SELECT甚至不需要引用任何 table:
CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;
下面的示例定义一个视图,该视图从另一个 table 中选择两个列以及从这些列中计算出的 table 达式:
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语句不能引用准备好的语句参数。
-
定义中引用的任何 table 或视图都必须存在。如果在创建视图后删除了定义所引用的 table 或视图,则使用该视图会导致错误。要检查视图定义中是否存在此类问题,请使用CHECK TABLE语句。
-
该定义不能引用
TEMPORARY
table,并且您不能创建TEMPORARY
视图。 -
您不能将触发器与视图关联。
-
SELECT语句中列名的别名会对照最大列长度 64 个字符(而不是别名最大长度 256 个字符)进行检查。
视图定义中允许使用ORDER BY
,但是如果您使用具有自己的ORDER BY
的语句从视图中进行选择,则将忽略ORDER BY
。
对于定义中的其他选项或子句,它们被添加到引用该视图的语句的选项或子句中,但效果未定义。例如,如果视图定义包含LIMIT
子句,并且您使用具有自己的LIMIT
子句的语句从视图中进行选择,则不确定哪个限制适用。相同的原理适用于SELECT关键字后的选项(例如ALL
,DISTINCT
或SQL_SMALL_RESULT
)以及子句(例如INTO
,FOR UPDATE
,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
Feature 值是DEFINER
(默认值)和INVOKER
。这些 table 明所需的特权必须分别由定义或调用视图的用户拥有。
如果存在DEFINER
子句,则* user
值应为指定为'user_name'@'host_name'
,CURRENT_USER或CURRENT_USER()的 MySQL 帐户。允许的 user
*值取决于您所拥有的特权,如第 23.6 节“存储的对象访问控制”中所述。另请参阅该部分以获取有关视图安全性的其他信息。
如果省略DEFINER
子句,则默认定义器是执行CREATE VIEW语句的用户。这与显式指定DEFINER = CURRENT_USER
相同。
在视图定义中,CURRENT_USER函数默认返回视图的DEFINER
值。对于使用SQL SECURITY INVOKER
特性定义的视图,CURRENT_USER返回该视图的调用者的帐户。有关视图内用户审核的信息,请参见第 6.2.18 节“基于 SQL 的帐户活动审核”。
在以SQL SECURITY DEFINER
特性定义的存储例程中,CURRENT_USER返回该例程的DEFINER
值。如果视图定义包含DEFINER
值为CURRENT_USER,则这也会影响在此例程中定义的视图。
MySQL 检查查看特权,如下所示:
-
在视图定义时,视图创建者必须具有使用视图访问的顶级对象所需的特权。例如,如果视图定义引用 table 列,则创建者必须对定义的选择列 table 中的每一列都具有某些特权,并且对定义中其他位置使用的每一列都具有SELECT特权。如果定义引用存储的函数,则只能检查调用该函数所需的特权。只能在函数调用时检查其执行时所需的特权:对于不同的调用,可能会采用函数内的不同执行路径。
-
引用视图后,将根据
SQL SECURITY
特性分别为DEFINER
或INVOKER
来对照视图DEFINER
帐户或调用者所拥有的特权检查该视图访问的对象的特权。 -
如果对视图的引用导致执行存储的函数,则对在函数内执行的语句的特权检查取决于函数
SQL SECURITY
是DEFINER
还是INVOKER
特性。如果安全特性为DEFINER
,则该函数将以DEFINER
帐户的特权运行。如果 Feature 是INVOKER
,则该函数将以视图的SQL SECURITY
Feature 确定的特权运行。
示例:视图可能取决于存储的函数,并且该函数可能调用其他存储的例程。例如,以下视图调用存储的函数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
的SQL SECURITY
值和函数f()
确定。
视图的DEFINER
和SQL SECURITY
子句是标准 SQL 的扩展。在标准 SQL 中,使用SQL SECURITY DEFINER
的规则处理视图。该标准说,视图的定义者与视图的架构所有者相同,它在视图上获得适用的特权(例如SELECT)并可以授予它们。 MySQL 没有模式“所有者”的概念,因此 MySQL 添加了一个子句来标识定义器。 DEFINER
子句是扩展,其目的是拥有标准所具有的内容;即是谁定义视图的永久记录。这就是默认DEFINER
值是视图创建者的帐户的原因。
可选的ALGORITHM
子句是标准 SQL 的 MySQL 扩展。它影响 MySQL 处理视图的方式。 ALGORITHM
采用三个值:MERGE
,TEMPTABLE
或UNDEFINED
。有关更多信息,请参见第 23.5.2 节“视图处理算法”和第 8.2.2.4 节“通过合并或实现来优化派生 table 和视图引用”。
有些观点是可更新的。也就是说,您可以在诸如UPDATE,DELETE或INSERT之类的语句中使用它们来更新基础 table 的内容。为了使视图可更新,视图中的行与基础 table 中的行之间必须存在一对一的关系。还有某些其他构造会使视图不可更新。
视图中的生成列被认为是可更新的,因为可以对其进行分配。但是,如果显式更新了此列,则唯一允许的值为DEFAULT
。有关生成的列的信息,请参见第 13.1.18.7 节“创建 table 和生成的列”。
可以为可更新视图提供WITH CHECK OPTION
子句,以防止对* select_statement
*中WHERE
子句为 true 的行进行插入或更新。
在可更新视图的WITH CHECK OPTION
子句中,当使用另一个视图定义视图时,LOCAL
和CASCADED
关键字确定检查测试的范围。关键字LOCAL
仅将CHECK OPTION
限制为正在定义的视图。 CASCADED
也会评估对基础视图的检查。如果没有给出任何关键字,则默认值为CASCADED
。
有关可更新视图和WITH CHECK OPTION
子句的更多信息,请参见第 23.5.3 节“可更新和可插入的视图”和第 23.5.4 节“带有检查选项子句的视图”。
在包含ORDER BY integer
的 MySQL 5.7.3 之前创建的视图可能会在视图评估时导致错误。请考虑以下视图定义,它们使用ORDER BY
以及序数:
CREATE VIEW v1 AS SELECT x, y, z FROM t ORDER BY 2;
CREATE VIEW v2 AS SELECT x, 1, z FROM t ORDER BY 2;
在第一种情况下,ORDER BY 2
指的是命名列y
。在第二种情况下,它引用常量 1.对于从任一视图中选择少于 2 列(在ORDER BY
子句中命名的数字)的查询,如果服务器使用 MERGE 算法评估视图,则会发生错误。例子:
mysql> SELECT x FROM v1;
ERROR 1054 (42S22): Unknown column '2' in 'order clause'
mysql> SELECT x FROM v2;
ERROR 1054 (42S22): Unknown column '2' in 'order clause'
从 MySQL 5.7.3 开始,为了处理这样的视图定义,服务器将它们不同地写入存储视图定义的.frm
文件中。此差异在显示创建视图可见。以前,.frm
文件包含ORDER BY 2
子句的内容:
For v1: ORDER BY 2
For v2: ORDER BY 2
从 5.7.3 开始,.frm
文件包含以下内容:
For v1: ORDER BY `t`.`y`
For v2: ORDER BY ''
也就是说,对于v1
,将 2 替换为对所引用列名称的引用。对于v2
,将 2 替换为常量字符串 table 达式(按常量排序无效,因此按任何常量排序都可以)。
如果遇到如上所述的视图评估错误,请删除并重新创建视图,以使.frm
文件包含更新的视图 table 示形式。另外,对于像v2
这样按恒定值排序的视图,请删除并重新创建没有ORDER BY
子句的视图。