写在前面

本篇来学习视图,对于开发人员来说这个在实际工作中用的不是很多,但是对于BI大数据人员来说,使用的频率还是较高的,因此本篇来学习一下MySQL中视图的相关内容。

本文的主要内容如下:(1)视图概念;(2)使用场景;(3)视图和表的区别;(4)视图好处;(5)创建视图;(6)修改视图;(7)删除视图;(8)查询视图结构;(9)更新视图;(10)文章总结。

需求说明

假设你在一个电商公司任职,领导想知道当月订单总金额、订单数量、购买年龄层次、购买者男女比例等?对于领导来说,他只关心数据,并不关心你如何实现的?因此你不能将写好的SQL语句给它,但是你却需要显示结果?此时就可以使用本篇讲到的视图,使用视图可以隐藏SQL执行的细节,只展示最终的运行结果。

视图

概念

视图是MySQL5出现的一种虚拟表,行和列的数据来源于定义视图时使用的表,也就是说视图的数据是在使用视图时动态生成的,视图只保存了SQL的执行逻辑,不保存SQL的执行结果。

使用场景

当多个地方需要使用到相同的查询结果时,且该查询结果较为复杂的时候,此时就可以使用视图来隐藏其复杂的具体实现细节。

视图和表的区别

接下来聊一聊视图和表的区别,这里主要从语法格式、保存内容和使用操作等三个方面来进行对比:

名称 语法格式 保存内容 使用操作
视图 create view 仅保存SQL逻辑 增删改查,实际上只使用查询
create table 保存数据 增删改查

好处

使用视图不仅简化了复杂的SQL操作,还隔离了原始表,使用视图无需接触原始表,提高了数据的安全性。

数据准备

为了后续学习的必要,这里先准备了五张表,这5张表在企业中用的较多,分别是:部门表(departments)、员工信息表(employees)、职位表(jobs)、位置表(locations)和薪资等级表(job_grades)。

第一步,创建对应的数据表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
drop database if exists `hellobook`;

create database `hellobook`;

USE `hellobook`;

/*部门表*/
DROP TABLE IF EXISTS `departments`;
CREATE TABLE `departments` (
`department_id` int(4) NOT NULL AUTO_INCREMENT comment '部门id',
`department_name` varchar(3) DEFAULT NULL comment '部门名称',
`manager_id` int(6) DEFAULT NULL comment '管理者id',
`location_id` int(4) DEFAULT NULL comment '部门位置id,来源于表locations中的location_id',
PRIMARY KEY (`department_id`),
KEY `loc_id_fk` (`location_id`)
) ENGINE=InnoDB AUTO_INCREMENT=271 comment '部门表';


/*员工表*/
DROP TABLE IF EXISTS `employees`;
CREATE TABLE `employees` (
`employee_id` int(6) NOT NULL AUTO_INCREMENT comment '员工id',
`first_name` varchar(20) DEFAULT NULL comment '名',
`last_name` varchar(25) DEFAULT NULL comment '姓',
`email` varchar(25) DEFAULT NULL comment '电子邮箱',
`phone_number` varchar(20) DEFAULT NULL comment '手机',
`job_id` varchar(10) DEFAULT NULL comment '职位id,来源于jobs表中的job_id',
`salary` double(10,2) DEFAULT NULL comment '薪水',
`commission_pct` double(4,2) DEFAULT NULL comment '佣金百分比',
`manager_id` int(6) DEFAULT NULL comment '上级id',
`department_id` int(4) DEFAULT NULL comment '所属部门id,来源于departments中的department_id',
`hiredate` datetime DEFAULT NULL comment '入职日期',
PRIMARY KEY (`employee_id`)
) ENGINE=InnoDB AUTO_INCREMENT=207 comment '员工表';


/*职位信息表*/
DROP TABLE IF EXISTS `jobs`;
CREATE TABLE `jobs` (
`job_id` varchar(10) NOT NULL comment '职位id',
`job_title` varchar(35) DEFAULT NULL comment '职位名称',
`min_salary` int(6) DEFAULT NULL comment '薪资范围最小值',
`max_salary` int(6) DEFAULT NULL comment '薪资范围最大值',
PRIMARY KEY (`job_id`)
) ENGINE=InnoDB comment '职位id';


/*位置表*/
DROP TABLE IF EXISTS `locations`;
CREATE TABLE `locations` (
`location_id` int(11) NOT NULL AUTO_INCREMENT comment '位置id',
`street_address` varchar(40) DEFAULT NULL comment '街道地址',
`postal_code` varchar(12) DEFAULT NULL comment '邮编',
`city` varchar(30) DEFAULT NULL comment '城市名称',
`state_province` varchar(25) DEFAULT NULL comment '省',
`country_id` varchar(2) DEFAULT NULL comment '国家编号',
PRIMARY KEY (`location_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3201 comment '位置表';


/*薪资等级表*/
DROP TABLE IF EXISTS `job_grades`;
CREATE TABLE `job_grades`(
`grade_level` varchar(3) comment '等级',
`lowest_sal` int comment '薪资最低值',
`highest_sal` int comment '薪资最高值',
PRIMARY KEY (`grade_level`)
) comment '薪资等级表';

第二步,插入数据,数据在Gitee上,因此这里就忽略,且这里的数据就是前面在学习子查询时的数据。

创建视图

创建视图的语法格式如下所示:

1
create view 视图名 as 查询语句;

也就是说使用视图分为两个步骤,第一步是创建视图;第二步是对视图执行查询操作。

例子1:查询姓名中包含a字符的员工名称、部门和工作名称。

第一步,创建视图myview1:

1
2
3
4
5
create view myview1 as
select e.last_name,d.department_name,j.job_title
from employees as e,jobs as j,departments as d
where e.employee_id = d.department_id
and e.job_id = j.job_id;

第二步,使用视图,如下所示:

1
select * from myview1 as m1 where m1.last_name like '%a%';

运行结果如下所示:

当然开发者也可以直接创建视图,此时SQL如下所示:

1
2
3
4
5
6
create view myview1 as
select e.last_name,d.department_name,j.job_title
from employees as e,jobs as j,departments as d
where e.last_name like '%a%'
and e.employee_id = d.department_id
and e.job_id = j.job_id;

但是这种方式不太建议使用,因为它将条件查询内嵌进去,不利于SQL的扩展,因此建议使用前面所说的两步走,即第一步,创建视图;第二步,对视图执行查询操作。

在上面我们创建了一个视图myview1,当需要查看包含a字符的员工名称、部门和工作名称时,无需关注这个视图内部是如何实现的,只需要查询视图即可。

例子2:查询各个部门的平均工资级别,显示部门id、平均工资和工资级别。

第一步,创建视图myview2:

1
2
3
4
5
6
create view myview2 as
select e.department_id as 部门id,e.asvg as 平均工资,jg.grade_level as 工资级别
from (
select department_id, avg(salary)as asvg from employees group by department_id
) as e,job_grades as jg
where e.asvg between jg.lowest_sal and jg.highest_sal;

第二步,使用视图,如下所示:

1
select * from myview2;

运行结果如下所示:

修改视图

可以使用两种方法来对视图进行修改:如果视图存在则修改,不存在则创建;直接修改视图。

方法1:如果该视图存在,则修改;不存在则创建新的视图,此时使用的SQL语法格式如下所示:

1
create or replace view 视图名 as 查询语句;

例子3:查询每个job_id的平均薪水,显示job_id和平均薪水:

1
2
3
4
create or replace view myview3 as
select job_id,avg(salary) as avsg
from employees
group by job_id;

执行结果如下所示:

方法2:直接修改视图,此时使用的SQL语法格式如下所示:

1
alter view 视图名 as 查询语句;

例子4:修改之前例子3的视图,使之查询员工信息表信息:

1
alter view myview3 as select * from employees;

执行结果如下所示(部分):

删除视图

删除视图的语法规则如下所示:

1
drop view 视图1[,视图1][,视图1=n];

开发者可以同时删除多个视图,多个视图名称之间使用逗号进行分隔。

例子5:删除之前创建的视图myview1、myview2和myview3:

1
drop view myview1,myview2,myview3;

查询视图结构

查询视图的结构有两种方法,第一种是使用desc 视图名称;;第二种是使用`show create view 视图名称;。

例子6:查看之前创建的myview1视图结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> desc myview1;
+-----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| last_name | varchar(25) | YES | | NULL | |
| department_name | varchar(3) | YES | | NULL | |
| job_title | varchar(35) | YES | | NULL | |
+-----------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> show create view myview1;
+---------+---------------------------------
| View | Create View | character_set_client | collation_connection |
+---------+--------------------------------------
| myview1 | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `myview1` AS select `e`.`last_name` AS `last_name`,`d`.`department_name` AS `department_name`,`j`.`job_title` AS `job_title` from ((`employees` `e` join `jobs` `j`) join `departments` `d`) where ((`e`.`last_name` like '%a%') and (`e`.`employee_id` = `d`.`department_id`) and (`e`.`job_id` = `j`.`job_id`)) | utf8 | utf8_general_ci |
+---------+--------------------------
1 row in set (0.00 sec)

desc关键字可以显示视图的字段信息,而show create view子句则显示了视图的创建语句。仔细观察可以发现这个其实和查看表的结构语句非常相似,不同的是将table修改为了view。

更新视图

接下来了解一下视图的更新,请注意视图的更新是更改视图中的数据,而不是更改视图中的SQL逻辑。对视图的进行更新后,也会对原始表的数据进行更新。因此为了防止对原始表的数据产生更新,开发者可以为视图添加只读权限,这样用户只能读取视图,而不能对视图进行更新。在正常情况下,我们很少多视图进行更新操作,因此这个了解一下就行。

例子7:接下来通过一个视图来总结和演示视图的使用操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
--创建视图
create or replace view myview4 as
select last_name,email from employees;

--插入数据
insert into myview4 values('envy','envythink@qq.com');

--查询数据
mysql> select * from myview4 where email like '%envy%';
+-----------+------------------+
| last_name | email |
+-----------+------------------+
| envy | envythink@qq.com |
+-----------+------------------+
1 row in set (0.00 sec)

--修改数据
mysql> update myview4 set last_name = 'book' where last_name ='envy';
Query OK, 1 row affected (0.17 sec)
Rows matched: 1 Changed: 1 Warnings: 0

--查询数据
mysql> select * from myview4 where email like '%envy%';
+-----------+------------------+
| last_name | email |
+-----------+------------------+
| book | envythink@qq.com |
+-----------+------------------+
1 row in set (0.00 sec)


--删除数据
mysql> delete from myview4 where last_name = 'book';
Query OK, 1 row affected (0.68 sec)
--查询数据
mysql> select * from myview4 where email like '%envy%';
Empty set (0.00 sec)

由于视图的更新可能导致较为严重的问题产生,因此在企业实际开发过程中视图更新操作用的不是很多。

其实不光是视图更新操作,在实际开发过程中视图本身用的也就不多,因此本篇只是了解一些视图的相关内容。

文章总结

本篇主要介绍了视图的一些概念,用途以及它和表的区别,并在此基础上学习了如何创建、使用、修改和删除视图,尽管视图本身在实际工作中用的不太多,但是在某些特殊场合下,使用视图可以解决一些问题。