注:本文使用mysql5.5版本为例。
做过数据库开发的同学,对视图(VIEW)应该不会陌生。
我接触视图最多的应用场景有两个:
1)出于权限问题,为了限制访问者看到过多的表字段(或内容),就建立一个视图供TA使用。
2)也可以为了查询方便,将多张表合并到一个视图里使用。
比如,我最近遇到一个这样的需求:
有四种用户类型的表,有部分相同的信息,当然也会有很多不相同的字段:
T_USER_PERSON(ID, PERSON_NAME, CREATE_TIME, …)
T_USER_TEAM(ID, TEAM_NAME, CREATE_TIME, …)
T_USER_COMPANY(ID, COMPANY_NAME, CREATE_TIME, ...)
T_USER_ORGANIZATION(ID, ORGANIZATION_NAME, CREATE_TIME, ...)
还有一张业务表,汇集了这四种用户分别创建的业务数据:
T_BUSSINESS(ID, USER_ID, USER_TYPE, CONTENT, ...)
USER_TYPE 是枚举类型:PERSON, TEAM, COMPANY, ORGANIZATION
由USER_ID和USER_TYPE来关联哪类的哪个用户,创建了这条业务数据。
关系图大概是这样的:
我第一个就想到了使用视图➡建立一个视图统一管理所有用户,再跟业务表关联查询,业务逻辑多么清晰!
于是,我建立这张视图,如下:
CREATE OR REPLACE VIEW VIEW_ALL_TYPE_USER as
select id id, PERSON_NAME user_name, 'PERSON' user_type, create_time create_time from T_USER_PERSON
UNION ALL
select id as id, COMPANY_NAME as user_name, 'COMPANY' as user_type, create_time create_time from T_USER_COMPANY
UNION ALL
select id as id, ORGANIZATION_NAME as user_name, 'ORGANIZATION' as user_type, create_time create_time from T_USER_ORGANIZATION
UNION ALL
select id as id, TEAM_NAME as user_name, 'TEAM' as user_type, create_time create_time from T_USER_TEAM;
改变之后的关系图大概是这样的:
联合查询的sql语句如下:
select b.id, b.user_id, v.user_name, b.content
from T_BUSSINESS b
left join VIEW_ALL_TYPE_USER v ON b.user_id=v.user_id and b.user_type=v.user_type
order by b.id desc
看起来很简洁,但是运行起来就慢得要死。其实数据量并不大,用户总共大概有12万,业务数据大概1400条。可是,经过视图和表的关联查询,速度是不可以忍受的,我想,这是多重笛卡尔积的结果吧。
除了联合查询效率低的问题,视图还不能建立索引,没办法有效提高查询效率。
经过再三权衡,我决定放弃视图,宁可使用稍微复杂一些的case-then语句来实现。效果还是可以的。
select b.id,
b.user_id,
b.user_type,
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end as user_name,
b.content
from T_BUSSINESS b
order by b.id desc
但是,这样的话,存在一个问题:
如果用别名作为查询条件,会出现错误:Unknown column 'user_name' in 'where clause'
1)把别名的查询条件放在table后面:
这种办法对我不起作用,不知道是否是版本的问题……
2)用一个select包起来:
注意:每个table,包括最终()起来的虚表都要起个别名
3)在查询条件里使用完整的case-then:
在本文中的sql语句应该是:
select b.id,
b.user_id,
b.user_type,
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end as user_name,
b.content
from T_BUSSINESS b
where
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end like '测试%'
order by b.id desc
-------------------
但是,好景不长,又遇到了问题……
新的需求来了,在外面又多了一层查询:
有多种相似的业务,想要放在一起进行排序展示。(这回我学“聪明”了,不考虑视图了)这样,就需要嵌套两层case-then语句……,先不考虑效率问题,这样冗长的SQL的可读性和维护性也太差了吧?
又经过再三权衡,我还是决定在业务表里增加一个user_name字段,虽然这是个冗余字段,但会使逻辑更简单,更易于维护。至于user_name数据一致性的问题,解决方法有很多:触发器/异步通知/同步更新等等,都可以实现。毕竟user_name并不是经常修改的。
最终的业务表是这样的(当然,其他的业务表也都增加了USER_NAME字段):
T_BUSSINESS(ID, USER_ID, USER_TYPE, USER_NAME, CONTENT, ...)
最后看起来大概是这个样子的:
至少,以我目前有限的认识,这样做是最佳方案,希望有更好方法的同学不吝赐教。
- MySql下视图的创建
(1).第一类:create view v as select * from table; (2).第二类:create view v as select id,name,age from ta ...
- MySQL之视图、触发器、事务、存储、函数、流程控制
一.视图 视图就是一个虚拟表,我们把复杂的sql语句后看到的虚拟表封装起来,给他取个名字,当我们下次使用的时候,就不用再去写复杂的sql语句,直接调用封装后的视图名字,就可以得到我们想要的表,然后就可 ...
- MySQL之视图、触发器、事务、存储过程、函数 流程控制
MySQL之视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上全部 ...
- 数据库MySQL之 视图、触发器、存储过程、函数、事务、数据库锁、数据库备份、事件
数据库MySQL之 视图.触发器.存储过程.函数.事务.数据库锁.数据库备份.事件 浏览目录 视图 触发器 存储过程 函数 事务 数据库锁 数据库备份 事件 一.视图 1.视图概念 视图是一个虚拟表, ...
- MySQL 的视图、触发器、事务、存储过程、函数
MySQL 的视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句 ...
- day 40 MySQL之视图、触发器、事务、存储过程、函数
MySQL之视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上 ...
- mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁
第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...
- mysql下的SELECT INTO语句
在mysql下使用SELECT INTO语句会产生ERROR 1327 (42000): Undeclared variable:new_tablename 此时要使用: CREATE TABLE C ...
- 第五章 MySQL事务,视图,索引,备份和恢复
第五章 MySQL事务,视图,索引,备份和恢复 一.事务 1.什么是事务 事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求.要么都执行 ...
随机推荐
- UVA 11889 - Benefit 可直接枚举
看题传送门 题目大意: 输入两个整数A和C,求最小的整数B,使得lcm(A,B)=C.如果无解,输出NO SOLUTION 思路: A*B=C*gcd(A,B) 所以 B / gcd(A,B) = C ...
- 7.1 基础知识Android消息处理机制
1. Android消息处理机制: Handler, MessageQueue, Looper, Thread 线程概念 : 一个应用程序运行时它的主体被称为进程, 一个进程内部可以有多个线程, 线程 ...
- mybatis+springmvc缓存设置
开始接触mybatis,本以为缓存设置好麻烦,在网上找了好多相关的资料,说得也都好复杂,经过自己亲自实践,其实很简单的. 首先引入需要的jar包,参照pom.xml配置: <!-- 缓存设置 s ...
- 关于心理的二十五种倾向(查理·芒格)-3
9)回馈倾向人们早就发现.和猿类,猴类,狗类等其它很多认知能力较为低下的物种同样,人类身上也有以德报德,以牙还牙的极端倾向:这样的倾向明显能够促进有利于成员利益的团体合作.这跟非常多社会性的动物的基因 ...
- [Angular2 Router] Setup page title with Router events
Article import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator ...
- [CSS] Target Positional Elements Using *-Of-Type CSS pseudo-classes
Learn how to target elements based on their position inside of a parent element in relation to its s ...
- 【Lucene4.8教程之五】Luke 2014-06-24 15:12 1092人阅读 评论(0) 收藏
一.Luke基本内容 1.Luke简介 Luke可用于查看Lucene创建的索引,并对其进行基本操作. 2.创建Luke (1)从Github上下载源文件 https://github.com/tar ...
- Docker入门之 - 如何安装Docker CE
原文:Docker入门之 - 如何安装Docker CE 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012055638/article/det ...
- 【u245】机房病毒
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 我们机房中了病毒,因此几乎什么都无法正常进入.为了解决这个病毒,我们花了好几天.终于在大家的共同努力下 ...
- 小强的HTML5移动开发之路(46)——汇率计算器【2】
在上一篇中我们完成了汇率计算页面,下面来完成汇率设置页面的显示. <div class="setRates"> <div class="header&q ...