MySQL视图(view)的基本用法及说明
作者:睿思达DBA_WGX
MySQL中的视图(view)是一种虚拟表,其内容由查询定义,是一个逻辑表,本身并不包含数据。
视图看起来和真实的表完全相同,但其中的数据来自定义视图时用到的基本表,并且在打开视图时动态生成。
视图可以在基本表上定义,也可以使用其他视图定义。与直接操作基本表相比,视图具备以下优点:
(1)简化操作:通过视图可以使用户将注意力集中在他所关心的数据上。使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件。
(2)提高数据的安全性:在设计数据库时可以针对不同的用户定义不同的视图,使用视图的用户只能访问他们被允许查询的结果集。
(3)数据独立:视图的结构定义好之后,如果增加新的关系或对原有的关系增加新的字段对用户访问的数据都不会造成影响。
一、创建视图的语法
创建视图的基本语法如下:
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION]
说明:
1、OR REPLACE:表示该语句能够替换已有视图;
2、ALGORITHM:可选参数,表示视图选择的算法,默认算法是UNDEFINED;
3、view_name:要创建的视图名称;
4、column_list:可选参数,表示视图的字段列表。如果省略,则使用select语句中的字段列表;
5、AS select_statement:创建视图的select语句;
6、WITH CHECK OPTION:表示更新视图时要保证该视图的WHERE子句为【真】。比如:定义视图create view v1 as select * from salary>5000;如果要更新视图,则必须保证salary字段的值在5000以上,否则报错;
二、数据准备
创建两张表:部门(dept)和员工(emp),并插入数据,代码如下:
create table dept( dept_id int primary key auto_increment comment '部门编号', dept_name char(20) comment '部门名称' ); insert into dept(dept_name) values('销售部'),('财务部'),('生产部'),('人事部'); create table emp( emp_id int primary key auto_increment comment '员工号', emp_name char(20) not null default '' comment '员工姓名', gender char(2) not null default '男' comment '性别', birth datetime not null default '1990-1-1' comment '出生日期', salary decimal(10,2) not null default 0 comment '工资', address varchar(200) not null default '' comment '通讯地址', dept_id int comment '部门编号' ); create index idx_name on emp(emp_name); create index idx_birth on emp(birth); create index idx_deptid_name on emp(dept_id,emp_name); insert into emp(emp_name,gender,birth,salary,address,dept_id) values('张晓红','女','1980-1-23',5800,'河南省郑州市中原路10号',1), ('张静静','女','1987-10-3',5400,'河南省新乡市平原路38号',1), ('王云飞','男','1992-11-15',5600,'河南省新乡市人民路28号',1), ('王鹏飞','男','1987-10-1',6800,'河南省新乡市东明大道12号',1), ('王大鹏','男','1989-2-11',5900,'河南省郑州市东风路15号',1), ('王萌萌','女','1986-12-30',5000,'河南省开封市五一路14号',2), ('王大光','男','1988-11-8',6200,'河南省开封市八一路124号',2), ('王小明','男','1998-1-3',4800,'河南省驻马店市雪松路128号',2), ('王娜娜','女','1994-3-5',5200,'河南省驻马店市车站路2号',2), ('刘云飞','男','1992-8-13',6800,'河南省南阳市民生路255号',3), ('张陆军','男','1991-9-6',6200,'河南省南阳市张仲景路14号',3);
三、创建视图
(一)创建一个单表视图
mysql> create or replace view v_emp_dept_id_1 as select emp_name,address from emp where dept_id=1; Query OK, 0 rows affected (0.00 sec) mysql> select * from v_emp_dept_id_1; +-----------+-------------------------------------+ | emp_name | address | +-----------+-------------------------------------+ | 张晓红 | 河南省郑州市中原路10号 | | 张静静 | 河南省新乡市平原路38号 | | 王云飞 | 河南省新乡市人民路28号 | | 王大鹏 | 河南省郑州市东风路15号 | | 王鹏飞 | 河南省新乡市东明大道12号 | +-----------+-------------------------------------+ 5 rows in set (0.00 sec)
(二)创建一个多表视图
mysql> create or replace view v_emp_dept as select emp_name,address,dept_name from emp join dept on emp.dept_id=dept.dept_id where dept.dept_id=1; Query OK, 0 rows affected (0.00 sec) mysql> select * from v_emp_dept; +-----------+-------------------------------------+-----------+ | emp_name | address | dept_name | +-----------+-------------------------------------+-----------+ | 张晓红 | 河南省郑州市中原路10号 | 销售部 | | 张静静 | 河南省新乡市平原路38号 | 销售部 | | 王云飞 | 河南省新乡市人民路28号 | 销售部 | | 王大鹏 | 河南省郑州市东风路15号 | 销售部 | | 王鹏飞 | 河南省新乡市东明大道12号 | 销售部 | +-----------+-------------------------------------+-----------+ 5 rows in set (0.00 sec)
(三)指定视图中的列名
mysql> create or replace view v_dept_emp_count(dept_name,emp_count,avg_salary) as select dept_name,count(*),avg(salary) from empp join dept on emp.dept_id=dept.dept_id group by dept.dept_name; Query OK, 0 rows affected (0.01 sec) mysql> select * from v_dept_emp_count; +-----------+-----------+-------------+ | dept_name | emp_count | avg_salary | +-----------+-----------+-------------+ | 生产部 | 2 | 6500.000000 | | 财务部 | 4 | 5300.000000 | | 销售部 | 5 | 5900.000000 | +-----------+-----------+-------------+ 3 rows in set (0.00 sec)
(四)指定WITH CHECK OPTION参数
mysql> create view v_emp_dept_produce as select emp_name,salary from emp -> where dept_id=(select dept_id from dept where dept_name='生产部') -> with check option; Query OK, 0 rows affected (0.01 sec) mysql> select * from v_emp_dept_produce; +-----------+---------+ | emp_name | salary | +-----------+---------+ | 刘云飞 | 6800.00 | | 张陆军 | 6200.00 | +-----------+---------+ 2 rows in set (0.01 sec)
四、查看视图
(一)利用show tables查看视图名称
mysql> show tables; +--------------------+ | Tables_in_test | +--------------------+ | area | | dept | | emp | | goods | | orders | | orders_logs | | t1 | | v1 | | v_dept_emp_count | | v_emp_dept | | v_emp_dept_id_1 | | v_emp_dept_produce | +--------------------+ 12 rows in set (0.00 sec)
(二)利用desc查看视图的字段信息
mysql> desc v_emp_dept; +-----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+-------+ | emp_name | char(20) | NO | | | | | address | varchar(200) | NO | | | | | dept_name | char(20) | YES | | NULL | | +-----------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
(三)利用show table status语句查看视图的基本信息
mysql> show table status like 'v_emp_dept'\G *************************** 1. row *************************** Name: v_emp_dept Engine: NULL Version: NULL Row_format: NULL Rows: NULL Avg_row_length: NULL Data_length: NULL Max_data_length: NULL Index_length: NULL Data_free: NULL Auto_increment: NULL Create_time: NULL Update_time: NULL Check_time: NULL Collation: NULL Checksum: NULL Create_options: NULL Comment: VIEW 1 row in set (0.01 sec)
(四)利用show create view命令查看视图的详细信息
mysql> show create view v_emp_dept\G *************************** 1. row *************************** View: v_emp_dept Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_emp_dept` AS select `emp`.`emp_name` AS `emp_name`,`emp`.`address` AS `address`,`dept`.`dept_name` AS `dept_name` from (`emp` join `dept` on((`emp`.`dept_id` = `dept`.`dept_id`))) where (`dept`.`dept_id` = 1) character_set_client: utf8 collation_connection: utf8_general_ci 1 row in set (0.00 sec)
五、修改视图
(一)使用create or replace view命令修改视图
mysql> create or replace view v_emp_dept as select emp_name,address,salary,dept_name -> from emp join dept on emp.dept_id=dept.dept_id where dept.dept_id=1 -> with check option; Query OK, 0 rows affected (0.00 sec) mysql> select * from v_emp_dept; +-----------+-------------------------------------+---------+-----------+ | emp_name | address | salary | dept_name | +-----------+-------------------------------------+---------+-----------+ | 张晓红 | 河南省郑州市中原路10号 | 5800.00 | 销售部 | | 张静静 | 河南省新乡市平原路38号 | 5400.00 | 销售部 | | 王云飞 | 河南省新乡市人民路28号 | 5600.00 | 销售部 | | 王大鹏 | 河南省郑州市东风路15号 | 5900.00 | 销售部 | | 王鹏飞 | 河南省新乡市东明大道12号 | 6800.00 | 销售部 | +-----------+-------------------------------------+---------+-----------+ 5 rows in set (0.00 sec)
(二)使用alter view命令修改视图
mysql> alter view v_emp_dept as select emp_name,address,salary,dept_name -> from emp join dept on emp.dept_id=dept.dept_id where dept.dept_id=1 -> order by salary desc with check option; Query OK, 0 rows affected (0.00 sec) mysql> select * from v_emp_dept; +-----------+-------------------------------------+---------+-----------+ | emp_name | address | salary | dept_name | +-----------+-------------------------------------+---------+-----------+ | 王鹏飞 | 河南省新乡市东明大道12号 | 6800.00 | 销售部 | | 王大鹏 | 河南省郑州市东风路15号 | 5900.00 | 销售部 | | 张晓红 | 河南省郑州市中原路10号 | 5800.00 | 销售部 | | 王云飞 | 河南省新乡市人民路28号 | 5600.00 | 销售部 | | 张静静 | 河南省新乡市平原路38号 | 5400.00 | 销售部 | +-----------+-------------------------------------+---------+-----------+ 5 rows in set (0.00 sec)
六、更新视图数据
因为视图时虚拟表,所以更新视图中的数据实际上是更新创建视图时用到的基本表中的数据。
(一)更新单表视图
mysql> select * from dept; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 1 | 销售部 | | 2 | 财务部 | | 3 | 生产部 | | 4 | 人事部 | +---------+-----------+ 4 rows in set (0.00 sec) mysql> select * from emp; +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ | emp_id | emp_name | gender | birth | salary | address | dept_id | +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ | 1 | 张晓红 | 女 | 1980-01-23 00:00:00 | 5800.00 | 河南省郑州市中原路10号 | 1 | | 2 | 张静静 | 女 | 1987-10-03 00:00:00 | 5400.00 | 河南省新乡市平原路38号 | 1 | | 3 | 王云飞 | 男 | 1992-11-15 00:00:00 | 5600.00 | 河南省新乡市人民路28号 | 1 | | 4 | 王鹏飞 | 男 | 1987-10-01 00:00:00 | 6800.00 | 河南省新乡市东明大道12号 | 1 | | 5 | 王大鹏 | 男 | 1989-02-11 00:00:00 | 5900.00 | 河南省郑州市东风路15号 | 1 | | 6 | 王萌萌 | 女 | 1986-12-30 00:00:00 | 5000.00 | 河南省开封市五一路14号 | 2 | | 7 | 王大光 | 男 | 1988-11-08 00:00:00 | 6200.00 | 河南省开封市八一路124号 | 2 | | 8 | 王小明 | 男 | 1998-01-03 00:00:00 | 4800.00 | 河南省驻马店市雪松路128号 | 2 | | 9 | 王娜娜 | 女 | 1994-03-05 00:00:00 | 5200.00 | 河南省驻马店市车站路2号 | 2 | | 10 | 刘云飞 | 男 | 1992-08-13 00:00:00 | 6800.00 | 河南省南阳市民生路255号 | 3 | | 11 | 张陆军 | 男 | 1991-09-06 00:00:00 | 6200.00 | 河南省南阳市张仲景路14号 | 3 | +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ 11 rows in set (0.00 sec) mysql> create view v_emp_1 as select emp_name,salary,address from emp where salary>6000; --不带 with check option 参数 Query OK, 0 rows affected (0.00 sec) mysql> select * from v_emp_1; +-----------+---------+-------------------------------------+ | emp_name | salary | address | +-----------+---------+-------------------------------------+ | 王鹏飞 | 6800.00 | 河南省新乡市东明大道12号 | | 王大光 | 6200.00 | 河南省开封市八一路124号 | | 刘云飞 | 6800.00 | 河南省南阳市民生路255号 | | 张陆军 | 6200.00 | 河南省南阳市张仲景路14号 | +-----------+---------+-------------------------------------+ 4 rows in set (0.00 sec) mysql> update v_emp_1 set salary=3000 where emp_name='王鹏飞'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from v_emp_1; +-----------+---------+-------------------------------------+ | emp_name | salary | address | +-----------+---------+-------------------------------------+ | 王大光 | 6200.00 | 河南省开封市八一路124号 | | 张陆军 | 6200.00 | 河南省南阳市张仲景路14号 | | 刘云飞 | 6800.00 | 河南省南阳市民生路255号 | +-----------+---------+-------------------------------------+ 3 rows in set (0.00 sec) mysql> select * from emp; +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ | emp_id | emp_name | gender | birth | salary | address | dept_id | +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ | 1 | 张晓红 | 女 | 1980-01-23 00:00:00 | 5800.00 | 河南省郑州市中原路10号 | 1 | | 2 | 张静静 | 女 | 1987-10-03 00:00:00 | 5400.00 | 河南省新乡市平原路38号 | 1 | | 3 | 王云飞 | 男 | 1992-11-15 00:00:00 | 5600.00 | 河南省新乡市人民路28号 | 1 | | 4 | 王鹏飞 | 男 | 1987-10-01 00:00:00 | 3000.00 | 河南省新乡市东明大道12号 | 1 | | 5 | 王大鹏 | 男 | 1989-02-11 00:00:00 | 5900.00 | 河南省郑州市东风路15号 | 1 | | 6 | 王萌萌 | 女 | 1986-12-30 00:00:00 | 5000.00 | 河南省开封市五一路14号 | 2 | | 7 | 王大光 | 男 | 1988-11-08 00:00:00 | 6200.00 | 河南省开封市八一路124号 | 2 | | 8 | 王小明 | 男 | 1998-01-03 00:00:00 | 4800.00 | 河南省驻马店市雪松路128号 | 2 | | 9 | 王娜娜 | 女 | 1994-03-05 00:00:00 | 5200.00 | 河南省驻马店市车站路2号 | 2 | | 10 | 刘云飞 | 男 | 1992-08-13 00:00:00 | 6800.00 | 河南省南阳市民生路255号 | 3 | | 11 | 张陆军 | 男 | 1991-09-06 00:00:00 | 6200.00 | 河南省南阳市张仲景路14号 | 3 | +--------+-----------+--------+---------------------+---------+--------------------------------------+---------+ 11 rows in set (0.00 sec) mysql> create or replace view v_emp_2 as select emp_name,salary,address -> from emp where salary>5500 with check option; --添加 with check option 参数 Query OK, 0 rows affected (0.01 sec) mysql> select * from v_emp_2; +-----------+---------+-------------------------------------+ | emp_name | salary | address | +-----------+---------+-------------------------------------+ | 张晓红 | 5800.00 | 河南省郑州市中原路10号 | | 王云飞 | 5600.00 | 河南省新乡市人民路28号 | | 王大鹏 | 5900.00 | 河南省郑州市东风路15号 | | 王大光 | 6200.00 | 河南省开封市八一路124号 | | 刘云飞 | 6800.00 | 河南省南阳市民生路255号 | | 张陆军 | 6200.00 | 河南省南阳市张仲景路14号 | +-----------+---------+-------------------------------------+ 6 rows in set (0.00 sec) mysql> update v_emp_2 set salary=3000 where emp_name='王云飞'; ERROR 1369 (HY000): CHECK OPTION failed 'test.v_emp_2' ---由于违反了视图定义的条件,则更新失败
(二)更新多表视图
mysql> create view v_emp_dept_11 as select emp_name,salary,dept.* from emp,dept where emp.dept_id=dept.dept_id; Query OK, 0 rows affected (0.01 sec) mysql> select * from v_emp_dept_11; +-----------+---------+---------+-----------+ | emp_name | salary | dept_id | dept_name | +-----------+---------+---------+-----------+ | 张晓红 | 5800.00 | 1 | 销售部 | | 张静静 | 5400.00 | 1 | 销售部 | | 王云飞 | 5600.00 | 1 | 销售部 | | 王鹏飞 | 3000.00 | 1 | 销售部 | | 王大鹏 | 5900.00 | 1 | 销售部 | | 王萌萌 | 5000.00 | 2 | 财务部 | | 王大光 | 6200.00 | 2 | 财务部 | | 王小明 | 4800.00 | 2 | 财务部 | | 王娜娜 | 5200.00 | 2 | 财务部 | | 刘云飞 | 6800.00 | 3 | 生产部 | | 张陆军 | 6200.00 | 3 | 生产部 | +-----------+---------+---------+-----------+ 11 rows in set (0.00 sec) mysql> update v_emp_dept_11 set salary=10000 where emp_name='张静静'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update v_emp_dept_11 set dept_name='销售事业部' where emp_name='张静静'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from v_emp_dept_11; +-----------+----------+---------+-----------------+ | emp_name | salary | dept_id | dept_name | +-----------+----------+---------+-----------------+ | 张晓红 | 5800.00 | 1 | 销售事业部 | | 张静静 | 10000.00 | 1 | 销售事业部 | | 王云飞 | 5600.00 | 1 | 销售事业部 | | 王鹏飞 | 3000.00 | 1 | 销售事业部 | | 王大鹏 | 5900.00 | 1 | 销售事业部 | | 王萌萌 | 5000.00 | 2 | 财务部 | | 王大光 | 6200.00 | 2 | 财务部 | | 王小明 | 4800.00 | 2 | 财务部 | | 王娜娜 | 5200.00 | 2 | 财务部 | | 刘云飞 | 6800.00 | 3 | 生产部 | | 张陆军 | 6200.00 | 3 | 生产部 | +-----------+----------+---------+-----------------+ 11 rows in set (0.00 sec)
七、删除视图
drop view [if exists] view_name; drop view v_emp_dept_11;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。