天天看点

如何在MySQL中创建视图?

create [or replace] [algorithm = {undefined | merge | temptable}]    viewview_name[(column_list)]    asselect_statement    [with [cascaded | local] check option]

该语句能创建新的视图,如果给定了or replace子句,该语句还能替换已有的视图。select_statement是一种select语句,它给出了视图的定义。该语句可从基表或其他视图进行选择。

该语句要求具有针对视图的create view权限,以及针对由select语句选择的每一列上的某些权限。对于在select语句中其他地方使用的列,必须具有select权限。如果还有or replace子句,必须在视图上具有drop权限。

视图属于数据库。在默认情况下,将在当前数据库创建新视图。要想在给定数据库中明确创建视图,创建时,应将名称指定为db_name.view_name。

表和视图共享数据库中相同的名称空间,因此,数据库不能包含具有相同名称的表和视图。

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

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

对于select语句中不合格的表或视图,将根据默认的数据库进行解释。通过用恰当的数据库名称限定表或视图名,视图能够引用表或其他数据库中的视图。

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

视图定义服从下述限制:

·         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子句。

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

create algorithm = merge view v_merge (vc1, vc2) asselect 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算法要求视图中的行和基表中的行具有一对一的关系。如果不具有该关系。必须使用临时表取而代之。如果视图包含下述结构中的任何一种,将失去一对一的关系:

·         distinct

·         group by

·         having

·         union或union all

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

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

·         聚合函数(sum(), min(), max(), count()等)。

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

·         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检查选项,因此,不仅会针对它自己的检查对插入项进行测试,也会针对基本视图的检查对插入项进行测试。在下面的语句中,介绍了这些差异: