MySQL CREATE VIEW

2013-06-04_165400

这是MySQL 5实力养成暨评量里的8-06.‘下列对于检视表(View)的叙述,何者正确?’

答案:(A) SELECT语句中的FROM子句,不能包含子查询 (B) SELECT语句不能引用系统变数

[adsense][/adsense]

请直接参考MySQL 5.7 Reference Manual :: 13 SQL Statement Syntax :: 13.1 Data Definition Statements :: 13.1.16 CREATE VIEW Syntax

MySQL 5.1参考手册 :: 22. 视图::22.2. CREATE VIEW语法

转译繁体中文于下:

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

该语句能建立新的检视表,如果给定了OR REPLACE子句,该语句还能替换已有的检视表。select_statement是一种SELECT语句,它给出了检视表的定义。该语句可从基资料表或其他检视表进行选择。

该语句要求具有针对检视表的CREATE VIEW权限,以及针对由SELECT语句选择的每一列上的某些权限。对于在SELECT语句中其他地方使用的列,必须具有SELECT权限。如果还有OR REPLACE子句,必须在检视表上具有DROP权限。

检视表属于资料库。在预设情况下,将在当前资料库建立新检视表。要想在给定资料库中明确建立检视表,建立时,应将名称指定为db_name.view_name

mysql> CREATE VIEW test.v AS SELECT * FROM t;

资料表和检视表共享资料库中相同的名称空间,因此,资料库不能包含具有相同名称的资料表和检视表

检视表必须具有唯一的栏位名,不得有重复,就像基资料表那样。预设情况下,由SELECT语句检索的栏位名将用作检视表栏位名。要想为检视表栏位定义明确的名称,可使用可选的column_list子句,列出由逗号隔开的ID。column_list中的名称数目必须等于SELECT语句检索的栏位数。

SELECT语句检索的栏位可以是对资料表栏位的简单引用。也可以是使用函数、常量值、操作符等的资料表达式。

对于SELECT语句中不合格的资料表或检视表,将根据预设的资料库进行解释。通过用恰当的资料库名称限定资料表或检视表名,检视表能够引用资料表或其他资料库中的检视表。

能够使用多种SELECT语句建立检视表。检视表能够引用基资料表或其他检视表。它能使用联合、UNION和子查询。SELECT甚至不需引用任何资料表。在下面的示范中,定义了从另一资料表选择两列的检视表,并给出了根据这些栏位计算的资料表达式:

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语句不能包含FROM子句中的子查询

·         SELECT语句不能引用系统或用户变数

·         SELECT语句不能引用预处理语句参数。

·         在预储程式内,定义不能引用预储程式参数或局部变数。

·         在定义中引用的资料表或检视表必须存在。但是,建立了检视表后,能够舍弃定义引用的资料表或检视表。要想检查检视表定义是否存在这类问题,可使用CHECK TABLE语句。

·         在定义中不能引用TEMPORARY资料表,不能建立TEMPORARY检视表。

·         在检视表定义中命名的资料表必须已存在。

·         不能将触发程序与检视表关联在一起

在检视表定义中允许使用ORDER BY,但是,如果从特定检视表进行了选择,而该检视表使用了具有自己ORDER BY的语句,它将被忽略。

对于定义中的其他选项或子句,它们将被增加到引用检视表的语句的选项或子句中,但效果未定义。例如,如果在检视表定义中包含LIMIT子句,而且从特定检视表进行了选择,而该检视表使用了具有自己LIMIT子句的语句,那么对使用哪个LIMIT未作定义。相同的原理也适用于其他选项,如跟在SELECT关键字后的ALL、DISTINCT或SQL_SMALL_RESULT,并适用于其他子句,如INTO、FOR UPDATE、LOCK IN SHARE MODE、以及PROCEDURE。

如果建立了检视表,并通过更改系统变数更改了查询处理环境,会影响从检视表获得的结果:

mysql> CREATE VIEW v AS SELECT CHARSET(CHAR(65)), COLLATION(CHAR(65));
Query OK, 0 rows affected (0.00 sec)

mysql> SET NAMES 'latin1';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| latin1            | latin1_swedish_ci   |
+-------------------+---------------------+
1 row in set (0.00 sec)

mysql> SET NAMES 'utf8';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| utf8              | utf8_general_ci     |
+-------------------+---------------------+
1 row in set (0.00 sec)

可选的ALGORITHM子句是对标准SQL的MySQL延伸。ALGORITHM可取三个值:MERGE、TEMPTABLE或UNDEFINED。如果没有ALGORITHM子句,预设算法是UNDEFINED(未定义的)。算法会影响MySQL处理检视表的方式。

对于MERGE,会将引用检视表的语句的文本与检视表定义合并起来,使得检视表定义的某一部分取代语句的对应部分。

对于TEMPTABLE,检视表的结果将被置于临时资料表中,然后使用它执行语句。

对于UNDEFINED,MySQL将选择所要使用的算法。如果可能,它倾向于MERGE而不是TEMPTABLE,这是因为MERGE通常更有效,而且如果使用了临时资料表,检视表是不可更新的。

明确选择TEMPTABLE的1个原因在于,建立临时资料表之后、并在完成语句处理之前,能够释放基资料表上的锁定。与MERGE算法相比,锁定释放的速度更快,这样,使用检视表的其他客户端不会被屏蔽过长时间。

检视表算法可以是UNDEFINED,有三种方式:

·         在CREATE VIEW语句中没有ALGORITHM子句。

·         CREATE VIEW语句有1个显式ALGORITHM = UNDEFINED子句。

·         为仅能用临时资料表处理的检视表指定ALGORITHM = MERGE。在这种情况下,MySQL将生成告警,并将算法设置为UNDEFINED。

正如前面所介绍的那样,通过将检视表定义中的对应部分合并到引用检视表的语句中,对MERGE进行处理。在下面的示范中,简要介绍了MERGE的工作方式。在该示范中,假定有1个具有下述定义的检视表v_merge:

CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS
SELECT c1, c2 FROM t WHERE c3 > 100;

示范1:假定发出了下述语句:

SELECT * FROM v_merge;

MySQL以下述方式处理语句:

·         v_merge成为t

·         *成为vc1、vc2,与c1、c2对应

·         增加检视表WHERE子句

所产生的将执行的语句为:

SELECT c1, c2 FROM t WHERE c3 > 100;

示范2:假定发出了下述语句:

SELECT * FROM v_merge WHERE vc1 < 100;

该语句的处理方式与前面介绍的类似,但vc1 < 100变为c1 < 100,并使用AND连接词将检视表的WHERE子句新增到语句的WHERE子句中(增加了圆括号以确保以正确的优先顺序执行子句部分)。所得的将要执行的语句变为:

SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);

事实上,将要执行的语句是具有下述形式的WHERE子句:

WHERE (select WHERE) AND (view WHERE)

MERGE算法要求检视表中的行和基资料表中的行具有一对一的关系。如果不具有该关系。必须使用临时资料表取而代之。如果检视表包含下述结构中的任何一种,将失去一对一的关系:

·         聚合函数(SUM(), MIN(), MAX(), COUNT()等)。

·         DISTINCT

·         GROUP BY

·         HAVING

·         UNION或UNION ALL

·         仅引用文字值(在该情况下,没有基本资料表)。

某些检视表是可更新的。也就是说,可以在诸如UPDATE、DELETE或INSERT等语句中使用它们,以更新基资料表的内容。对于可更新的检视表,在检视表中的行和基资料表中的行之间必须具有一对一的关系。还有一些特定的其他结构,这类结构会使得检视表不可更新。更具体地讲,如果检视表包含下述结构中的任何一种,那么它就是不可更新的:

·         聚合函数(SUM(), MIN(), MAX(), COUNT()等)。

·         DISTINCT

·         GROUP BY

·         HAVING

·         UNION或UNION ALL

·         位于选择列资料表中的子查询

·         Join

·         FROM子句中的不可更新检视表

·         WHERE子句中的子查询,引用FROM子句中的资料表。

·         仅引用文字值(在该情况下,没有要更新的基本资料表)。

·         ALGORITHM = TEMPTABLE(使用临时资料表总会使检视表成为不可更新的)。

关于可插入性(可用INSERT语句更新),如果它也满足关于检视表栏位的下述额外要求,可更新的检视表也是可插入的:

·         不得有重复的检视表栏位名称。

·         检视表必须包含没有预设值的基资料表中的所有栏位。

·         检视表栏位必须是简单的栏位引用而不是导出栏位。导出栏位不是简单的栏位引用,而是从资料表达式导出的。下面给出了一些导出栏位示范:

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

混合了简单栏位引用和导出栏位的检视表是不可插入的,但是,如果仅更新非导出栏位,检视表是可更新的。考虑下述检视表:

CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;

该检视表是不可插入的,这是因为col2是从资料表达式导出的。但是,如果更新时不更新col2,它是可更新的。这类更新是允许的:

UPDATE v SET col1 = 0;

下述更新是不允许的,原因在于,它试图更新导出列:

UPDATE v SET col2 = 0;

在某些情况下,能够更新多资料表检视表,假定它能使用MERGE算法进行处理。为此,检视表必须使用内部联合(而不是外部联合或UNION)。此外,仅能更新检视表定义中的单个资料表,因此,SET子句必须仅命名视图中某一资料表的列。即使从理论上讲也是可更新的,不允许使用UNION ALL的检视,这是因为,在实施中将使用临时资料表来处理它们。

对于多资料表可更新检视表,如果是将其插入单个资料表中,INSERT能够工作。不支援DELETE。

对于可更新检视表,可给定WITH CHECK OPTION子句来防止插入或更新行,除非作用在行上的select_statement中的WHERE子句为“真”。

在关于可更新检视表的WITH CHECK OPTION子句中,当检视表是根据另一个检视表定义的时,LOCAL和CASCADED关键字决定了检查测试的范围。LOCAL关键字对CHECK OPTION进行了限制,使其仅作用在定义的检视表上,CASCADED会对将进行评估的基资料表进行检查。如果未给定任一关键字,预设值为CASCADED。请考虑下述资料表和检视表集合的定义:

mysql> CREATE TABLE t1 (a INT);
mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
    -> WITH CHECK OPTION;
mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
    -> WITH LOCAL CHECK OPTION;
mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
    -> WITH CASCADED CHECK OPTION;

这里,检视表v2和v3是根据另一检视表v1定义的。v2具有LOCAL检查选项,因此,仅会针对v2检查对插入项进行测试。v3具有CASCADED检查选项,因此,不仅会针对它自己的检查对插入项进行测试,也会针对基本检视表的检查对插入项进行测试。在下面的语句中,介绍了这些差异:

ql> INSERT INTO v2 VALUES (2);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO v3 VALUES (2);
ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'

检视表的可更新性可能会受到系统变数updatable_views_with_limit的值的影响。请参见5.3.3节,“伺服器系统变数”

INFORMATION_SCHEMA包含1个VIEWS资料表,从该资料表可获取关于检视表对象的讯息。请参见23.1.15节,“INFORMATION_SCHEMA VIEWS资料表”