Mysql视图使用总结
视图View使用总结:
视图可以看作为“虚拟表”,因为它返回的结果集格式与实体数据表返回的数据集格式类似,并且引用视图的方式与引用数据表的方式相同。每次查询使用视图时,DBMS会动态生成视图结果集所需要的逻辑合并到从基表数据生成的结果集逻辑中。(技术讨论群:276592700(新))
l 什么是视图?
l 视图的特点?
l 视图的类型?
l 视图的使用?
一、什么是视图
视图是一个从一张或几张数据表或视图中导出的虚拟表,它的作用类似于对数据表进行筛选,必须使用SQL语句中的SELECT语句实现构成。在定义视图时,只是把视图的定义存放在数据库,并不保存视图的数据,直到用户使用视图时才进行数据的查询并返回操作,当需要从不同的服务器中获得数据时,使用视图可以很好的将结构相同的数据组织并返回。
二、视图的特点
视图的主要特点如下:
1、简化数据的操作
用户可以将经常使用的连接,联合查询、及选择查询定义为视图,这样每次调用的时候,只需要简单的调用视图即可。另外,视图可以隐藏表表间的复杂关系。
2、可作为安全机制
视图可以用来做安全机制。用户可以通过设置视图,使特定的用户只能查看或修改他们权限内的数据,其它的数据库或表不能进行操作。视图的安全性可以防止未授权的用户查看或操作特定的列或行,通过在你表中设置一个用户的标志来建立视图,使用户只能查看或操作标志自己标志的列或行,从而保证数据的安全性。
3、合并及分割数据
有的时候,由于表中的数据量太大,需要对表进行拆分,这样会导致表的结构发生变化,导致用户的应用程序受到影响,这时我们就可以使用视图来屏蔽实体表间的逻辑关系,去构建应用程序所需要的原始表关系。
4、数据的倒入导出
实际项目中,我们经常会使用视图来组织和导入及导出操作,十分方便。
三、视图的类型
因为不同的数据库,例如:Mysql、Sql Server、Oracle及DB2等,他们不论在视图的创建和类型上都有不同,特别是在类型上区别较大,所以这里我们以Mysql来说明总结,至于其它数据的特点会在日后继续更新。
在Mysql中视图的类型分为:
1、MERGE
将视图的sql语句和引用视图的sql语句合并在一起,最后一起执行。
2、TEMPTABLE
将视图的结果集存放在临时表中,每次执行时从临时表中操作。
3、UNDEFINED
默认的视图类型,DBMS倾向于选择而不是必定选择MERGE,因为MERGE的效率更高,更重要的是临时表视图不能更新。
所以,这里推荐使用MERGE算法类型视图。
视图的特性
视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变);
可以跟基本表一样,进行增删改查操作(ps:增删改操作有条件限制);
视图的作用
方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;
更加安全,数据库授权命令不能限定到特定行和特定列,但是通过合理创建视图,可以把权限限定到行列级别
使用场合
权限控制的时候,不希望用户访问表中某些含敏感信息的列,比如salary...
关键信息来源于多个复杂关联表,可以创建视图提取我们需要的信息,简化操作;
现有三张表:用户(user)、课程(course)、用户课程中间表(user_course),表结构及数据如下:
表定义:
-- ---------------------------- -- Table structure for `course` -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(200) NOT NULL, `description` varchar(500) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of course -- ---------------------------- INSERT INTO `course` VALUES ('1', 'JAVA', 'JAVA课程'); INSERT INTO `course` VALUES ('2', 'C++', 'C++课程'); INSERT INTO `course` VALUES ('3', 'C语言', 'C语言课程'); -- ---------------------------- -- Table structure for `user` -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `address` varchar(255) DEFAULT NULL, `others` varchar(200) DEFAULT NULL, `others2` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'user1', '小陈', '美国', '1', '1'); INSERT INTO `user` VALUES ('2', 'user2', '小张', '日本', '2', '2'); INSERT INTO `user` VALUES ('3', 'user3', '小王', '中国', '3', '3'); -- ---------------------------- -- Table structure for `user_course` -- ---------------------------- DROP TABLE IF EXISTS `user_course`; CREATE TABLE `user_course` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `userid` bigint(20) NOT NULL, `courseid` bigint(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_course -- ---------------------------- INSERT INTO `user_course` VALUES ('1', '1', '2'); INSERT INTO `user_course` VALUES ('2', '1', '3'); INSERT INTO `user_course` VALUES ('3', '2', '1'); INSERT INTO `user_course` VALUES ('4', '2', '2'); INSERT INTO `user_course` VALUES ('5', '2', '3'); INSERT INTO `user_course` VALUES ('6', '3', '2');
表数据:
这时,当我们想要查询小张上的所以课程相关信息的时候,需要这样写一条长长的SQL语句,如下:
SELECT `uc`.`id` AS `id`, `u`.`name` AS `username`, `c`.`name` AS `coursename` FROM `user` `u` LEFT JOIN `user_course` `uc` ON ((`u`.`id` = `uc`.`userid`)) LEFT JOIN `course` `c` ON ((`uc`.`courseid` = `c`.`id`)) WHERE u.`name` = '小张'
但是我们可以通过视图简化操作,例如我们创建视图view_user_course如下:
-- ---------------------------- -- View structure for `view_user_course` -- ---------------------------- DROP VIEW IF EXISTS `view_user_course`; CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`localhost`
SQL SECURITY DEFINER VIEW `view_user_course` AS ( SELECT `uc`.`id` AS `id`, `u`.`name` AS `username`, `c`.`name` AS `coursename` FROM ( ( `user` `u` LEFT JOIN `user_course` `uc` ON ((`u`.`id` = `uc`.`userid`)) ) LEFT JOIN `course` `c` ON ((`uc`.`courseid` = `c`.`id`)) ) );
几点说明(MySQL中的视图在标准SQL的基础之上做了扩展):
ALGORITHM=UNDEFINED:指定视图的处理算法;
DEFINER=`root`@`localhost`:指定视图创建者;
SQL SECURITY DEFINER:指定视图查询数据时的安全验证方式;
创建好视图之后,我们可以直接用以下SQL语句在视图上查询小张上的所以课程相关信息,同样可以得到所需结果:
SELECT vuc.username, vuc.coursename FROM view_user_course vuc WHERE vuc.username = '小张'
视图实例2-增删改数据操作
继续,我们可以尝试在视图view_user_course上做增删改数据操作,如下:
update view_user_course set username='test',coursename='JAVASCRIPT' where id=3
遗憾的是操作失败,提示错误信息如下:
[SQL] update view_user_course set username='test',coursename='JAVASCRIPT' where id=3
[Err] 1393 - Can not modify more than one base table through a join view 'demo.view_user_course'
因为不能在一张由多张关联表连接而成的视图上做同时修改两张表的操作;
那么哪些操作可以在视图上进行呢?
视图与表是一对一关系情况:如果没有其它约束(如视图中没有的字段,在基本表中是必填字段情况),是可以进行增删改数据操作;
如我们创建用户关键信息视图view_user_keyinfo,如下:
-- ---------------------------- -- View structure for `view_user_keyinfo` -- ---------------------------- DROP VIEW IF EXISTS `view_user_keyinfo`; CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`localhost` SQL SECURITY DEFINER VIEW `view_user_keyinfo` AS SELECT `u`.`id` AS `id`, `u`.`account` AS `account`, `u`.`name` AS `username` FROM `user` `u`;
进行增删改操作如下,操作成功(注意user表中的其它字段要允许为空,否则操作失败):
INSERT INTO view_user_keyinfo (account, username) VALUES ('test1', 'test1');
DELETE FROM view_user_keyinfo WHERE username = 'test1';
UPDATE view_user_keyinfo SET username = 'updateuser' WHERE id = 1
视图与表是一对多关系情况:如果只修改一张表的数据,且没有其它约束(如视图中没有的字段,在基本表中是必填字段情况),是可以进行改数据操作,如以下语句,操作成功;
update view_user_course set coursename='JAVA' where id=1;
update view_user_course set username='test2' where id=3;
以下操作失败:
delete from view_user_course where id=3;
insert into view_user_course(username, coursename) VALUES('2','3');
其它
视图中的查询语句性能要调到最优;
修改操作时要小心,不经意间你已经修改了基本表里的多条数据;
其它性能相关方面待实践体会...
create view view_admin as ( select admin.id as id,admin.account as account,group_access.group_id as group_id,groups.title as role from think_admin admin left join think_auth_group_access group_access on admin.id=group_access.uid left join think_auth_group groups on group_access.group_id=groups.id);
修改视图CREATE OR REPLACE VIEW
create or replace view view_admin as ( select admin.id as id,admin.account as account,group_access.group_id as group_id,groups.title as role,group_access.rules as rules from think_admin admin left join think_auth_group_access group_access on admin.id=group_access.uid left join think_auth_group groups on group_access.group_id=groups.id);