上集唠叨了表中数据操做的一些语句,包括用于插入数据的INSERT
语句,用于删除数据的DELETE
语句,用于更新数据的UPDATE
语句。不过咱们以前说到的增删改查的语句都是一次性的,这些请求被包装成请求被客户端发到服务器,服务器处理后把结果返回给客户端以后就没有用了,本集将聚焦于如何让这些一次性的语句变得能够很容易的被重复使用。mysql
咱们以前唠叨过链接表的查询,比方说下边这个:程序员
mysql> SELECT s1.number, s1.name, s1.major, s2.subject, s2.score FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男';
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子腾 | 计算机科学与工程 | 母猪的产后护理 | 78 |
| 20180101 | 杜子腾 | 计算机科学与工程 | 论萨达姆的战争准备 | 88 |
| 20180103 | 范统 | 软件工程 | 母猪的产后护理 | 59 |
| 20180103 | 范统 | 软件工程 | 论萨达姆的战争准备 | 61 |
+----------+-----------+--------------------------+-----------------------------+-------+
4 rows in set (0.00 sec)
mysql>
复制代码
咱们查询出了一些男学生的基本信息和成绩信息,若是下次还想获得这些信息,咱们就不得不把这个又臭又长的查询语句再敲一遍,因此MySQL
提供了视图
(英文名VIEW
)来帮助咱们用很容易的方式去复用这些查询语句。sql
一个视图
能够理解为一个查询语句的别名,建立视图
的语句以下:数据库
CREATE VIEW 视图名 AS 查询语句
复制代码
好比咱们想根据上边那个又臭又长的查询语句来建立一个视图
能够这么写:bash
mysql> CREATE VIEW male_student_info AS SELECT s1.number, s1.name, s1.major, s2.subject, s2.score FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男';
Query OK, 0 rows affected (0.02 sec)
mysql>
复制代码
这样,这个名称为male_student_info
的视图就表明了那一串又臭又长的查询语句了。服务器
视图
也被称为虚拟表
,由于咱们能够对视图
进行一些相似表的增删改查操做,只不过咱们对视图的相关操做都会被映射到那个又臭又长的查询语句对应的底层的表上。那一串又臭又长的查询语句的查询列表能够被看成视图
的虚拟列
,比方说male_student_info
这个视图对应的查询语句中的查询列表是number
、name
、major
、subject
、score
,它们也是male_student_info
视图的虚拟列
。函数
好比咱们可使用日常的查询语句从视图
中查询咱们须要的信息能够这么写:学习
mysql> SELECT * FROM male_student_info;
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子腾 | 计算机科学与工程 | 母猪的产后护理 | 78 |
| 20180101 | 杜子腾 | 计算机科学与工程 | 论萨达姆的战争准备 | 88 |
| 20180103 | 范统 | 软件工程 | 母猪的产后护理 | 59 |
| 20180103 | 范统 | 软件工程 | 论萨达姆的战争准备 | 61 |
+----------+-----------+--------------------------+-----------------------------+-------+
4 rows in set (0.00 sec)
mysql>
复制代码
这里咱们的查询列表是*
,这也就意味着male_student_info
所表明的查询语句的结果集将做为整个查询的结果集返回。从这个例子中咱们也能够看到,咱们再也不须要使用那句又臭又长的链接查询语句了,只须要从它对应的视图
中查询便可。优化
除此以外,咱们在真实表中使用的那些查询语句均可以被用到视图
这个虚拟表中,比方说这个查询语句:ui
mysql> SELECT subject, AVG(score) FROM male_student_info WHERE score > 60 GROUP BY subject HAVING AVG(score) > 75 LIMIT 1;
+-----------------------+------------+
| subject | AVG(score) |
+-----------------------+------------+
| 母猪的产后护理 | 78.0000 |
+-----------------------+------------+
1 row in set (0.00 sec)
mysql>
复制代码
咱们再次强调一遍,视图
其实就是某个查询的别名,而不是某个查询的结果集,换句话说就是,建立视图的时候并不会把那个又臭又长的查询语句的结果集维护在硬盘或者内存里!在对视图进行查询时,MySQL
服务器将会帮助咱们把对视图的查询语句转换为对底层表的查询语句而后再执行,因此上边这个查询其实会被转换成下边这个查询语句去执行:
SELECT subject, AVG(score) FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男' AND score > 60 GROUP BY subject HAVING AVG(score) > 75;
复制代码
只不过这个转换的过程咱们并不能看到,因此主观上认为硬盘或内存里真的维护了一个视图对应的表而已~ 更复杂的一些查询语句,好比子查询、链接查询什么的,均可以被用到视图上,咱们这里就不举例子了。
有一点比较有趣的是,在查询时,视图能够和表一块儿使用,包括子查询和链接查询,好比这样:
mysql> SELECT * FROM male_student_info WHERE number IN (SELECT number FROM student_info WHERE major = '计算机科学与工程');
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子腾 | 计算机科学与工程 | 母猪的产后护理 | 78 |
| 20180101 | 杜子腾 | 计算机科学与工程 | 论萨达姆的战争准备 | 88 |
+----------+-----------+--------------------------+-----------------------------+-------+
2 rows in set (0.00 sec)
mysql>
复制代码
因此在使用层面,咱们彻底能够把视图
看成一个表去使用,可是它的实现原理倒是在执行语句时转换为对底层表的操做。使用视图的好处也是显而易见的,咱们能够复用某个查询语句,从而简化了查询操做,避免了每次查询时都要写一遍又臭又长的语句;对视图的操做更加直观,而不用考虑它底层的查询细节。
咱们前边说视图是某个查询语句的别名,其实这个查询语句不只能够从普通的表中查询数据,也能够从另外一个视图中查询数据,只要是个合法的查询语句就行了。比方说咱们利用male_student_info
视图来建立另外一个新视图能够这么写:
mysql> CREATE VIEW by_view AS SELECT number, name, score FROM male_student_info;
Query OK, 0 rows affected (0.02 sec)
mysql>
复制代码
咱们查询一下这个从另外一个视图中生成的视图:
mysql> SELECT * FROM by_view;
+----------+-----------+-------+
| number | name | score |
+----------+-----------+-------+
| 20180101 | 杜子腾 | 78 |
| 20180101 | 杜子腾 | 88 |
| 20180103 | 范统 | 59 |
| 20180103 | 范统 | 61 |
+----------+-----------+-------+
4 rows in set (0.00 sec)
mysql>
复制代码
这种利用其余的视图来生成的新视图也被称为嵌套视图
,在对某个嵌套视图
执行查询时,查询语句会先被转换成对它依赖的视图的查询,再转换成对底层表的查询。
咱们前边说过视图
的虚拟列
实际上是这个视图对应的查询语句的查询列表,咱们也能够在建立列表的时候为这些虚拟列
自定义列名,这些自定义列名写到视图名后边,用逗号,
分隔就行了,不过须要注意的是,自定义列名必定要和查询列表中的查询对象一一对应。好比咱们新建立一个自定义列名的视图:
mysql> CREATE VIEW student_info_view(no, n, m) AS SELECT number, name, major FROM student_info;
Query OK, 0 rows affected (0.02 sec)
mysql>
复制代码
咱们的自定义列名列表是no, n, m
,分别对应查询列表中的number, name, major
。有了自定义列名以后,咱们以后对视图的查询语句都要基于这些自定义列名,好比咱们能够这么查询:
mysql> SELECT no, n, m FROM student_info_view;
+----------+-----------+--------------------------+
| no | n | m |
+----------+-----------+--------------------------+
| 20180101 | 杜子腾 | 计算机科学与工程 |
| 20180102 | 杜琦燕 | 计算机科学与工程 |
| 20180103 | 范统 | 软件工程 |
| 20180104 | 史珍香 | 软件工程 |
| 20180105 | 范剑 | 飞行器设计 |
| 20180106 | 朱逸群 | 电子信息 |
+----------+-----------+--------------------------+
6 rows in set (0.00 sec)
mysql>
复制代码
若是仍旧使用与视图对应的查询语句的查询列表中的列名就会报错,好比这样:
mysql> SELECT number, name, major FROM student_info_view;
ERROR 1054 (42S22): Unknown column 'number' in 'field list'
mysql>
复制代码
咱们想查看当前数据库中有哪些视图的话,其实和查看有哪些表的命令是同样的:
mysql> SHOW TABLES;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| by_view |
| first_table |
| male_student_info |
| second_table |
| student_info |
| student_info_view |
| student_score |
| t |
| t1 |
| t2 |
| t3 |
| zero_table |
+---------------------+
12 rows in set (0.00 sec)
mysql>
复制代码
能够看到,咱们建立的几个视图,包括by_view
、male_student_info
、student_info_view
就都显示出来了。须要注意的是,由于视图是一张虚拟表
,因此新建立的视图的名称不能和当前数据库中的其余视图或者表的名称冲突!
由于视图是一张虚拟表
,因此用来查看表结构的语句均可以用来查看视图的结构,不过咱们常用的查看视图定义语句是这个:
SHOW CREATE VIEW 视图名
复制代码
咱们来查看一下student_info_view
视图的定义:
mysql> SHOW CREATE VIEW student_info_view\G
*************************** 1. row ***************************
View: student_info_view
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `student_info_view` AS select `student_info`.`number` AS `no`,`student_info`.`name` AS `n`,`student_info`.`major` AS `m` from `student_info`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.00 sec)
mysql>
复制代码
若是某个视图咱们不想要了,可使用这个语句来删除掉它:
DROP VIEW 视图名
复制代码
好比咱们把by_view
视图删掉能够这么写:
mysql> DROP VIEW by_view;
Query OK, 0 rows affected (0.00 sec)
mysql>
复制代码
而后再查看当前数据库中的表:
mysql> SHOW TABLES;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| first_table |
| male_student_info |
| second_table |
| student_info |
| student_info_view |
| student_score |
| t |
| t1 |
| t2 |
| t3 |
| zero_table |
+---------------------+
11 rows in set (0.00 sec)
mysql>
复制代码
这个视图就不见了!
咱们前边进行的都是对视图的查询操做,其实也能够对视图进行更新,也就是在视图上执行INSERT
、DELETE
、UPDATE
语句。对视图执行更新语句的本质上是对该视图对应的底层表进行更新。比方说视图student_info_view
的底层表是student_info
,因此若是咱们对student_info_view
执行更新语句就至关于对student_info
表进行更新,比方说咱们执行这个语句:
mysql> UPDATE student_info_view SET n = '111' WHERE no = 20180101;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql>
复制代码
咱们再到student_info
表中看一下这个学生的名称是否被改了:
mysql> SELECT name FROM student_info WHERE number = 20180101;
+------+
| name |
+------+
| 111 |
+------+
1 row in set (0.00 sec)
mysql>
复制代码
名称的确被更改为功了!
不过并非能够在全部的视图上执行更新语句的,在生成视图的时候使用了下边这些语句的都不能进行更新:
虽然有这么多限制,可是须要咱们注意的是,通常状况下,咱们只在视图上执行查询操做而不进行更新操做!这里介绍对视图的更新只是为了语法的完整性,并非建议你们在实际使用过程当中使用对视图的更新功能。
本系列专栏都是MySQL入门知识,想看进阶知识能够到小册中查看:《MySQL是怎样运行的:从根儿上理解MySQL》的连接 。小册的内容主要是从小白的角度出发,用比较通俗的语言讲解关于MySQL进阶的一些核心概念,好比记录、索引、页面、表空间、查询优化、事务和锁等,总共的字数大约是三四十万字,配有上百幅原创插图。主要是想下降普通程序员学习MySQL进阶的难度,让学习曲线更平滑一点~