注:本文使用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. MySql下视图的创建

     (1).第一类:create view v as select * from table; (2).第二类:create view v as select id,name,age from ta ...

  2. MySQL之视图、触发器、事务、存储、函数、流程控制

    一.视图 视图就是一个虚拟表,我们把复杂的sql语句后看到的虚拟表封装起来,给他取个名字,当我们下次使用的时候,就不用再去写复杂的sql语句,直接调用封装后的视图名字,就可以得到我们想要的表,然后就可 ...

  3. MySQL之视图、触发器、事务、存储过程、函数 流程控制

    MySQL之视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上全部 ...

  4. 数据库MySQL之 视图、触发器、存储过程、函数、事务、数据库锁、数据库备份、事件

    数据库MySQL之 视图.触发器.存储过程.函数.事务.数据库锁.数据库备份.事件 浏览目录 视图 触发器 存储过程 函数 事务 数据库锁 数据库备份 事件 一.视图 1.视图概念 视图是一个虚拟表, ...

  5. MySQL 的视图、触发器、事务、存储过程、函数

    MySQL 的视图.触发器.事务.存储过程.函数   阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句 ...

  6. day 40 MySQL之视图、触发器、事务、存储过程、函数

    MySQL之视图.触发器.事务.存储过程.函数   阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上 ...

  7. mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁

    第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...

  8. mysql下的SELECT INTO语句

    在mysql下使用SELECT INTO语句会产生ERROR 1327 (42000): Undeclared variable:new_tablename 此时要使用: CREATE TABLE C ...

  9. 第五章 MySQL事务,视图,索引,备份和恢复

    第五章 MySQL事务,视图,索引,备份和恢复 一.事务 1.什么是事务 事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求.要么都执行 ...

随机推荐

  1. Spring Boot Freemarker特别篇之contextPath【从零开始学Spring Boot】(转)

    需求缘起:有人在群里@我:请教群主大神一个问题,spring boot  + freemarker 怎么获取contextPath 头疼死我了,网上没一个靠谱的 .我就看看之前博客中的 [Spring ...

  2. [java面试]宇信易诚 广州分公司 java笔试题目回顾录

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/28479895 作者:sushengmiyan -------------------- ...

  3. MHA 一主两从搭建-keepalived-手动切换

    环境介绍:主机名 IP MHA角色 MySQL角色node1 192.168.56.26 Node MySQL Master node2 192.168.56.27 Node MySQL Master ...

  4. [Angular2 Form] Validation message for Reactive form

    <div class="form-field"> <label>Confirm Password: </label> <input typ ...

  5. 飘逸的python - property及实现lazy property

    @property有什么用呢?表面看来,就是将一个方法用属性的方式来訪问. 上代码,代码最清晰了. class Circle(object): def __init__(self, radius): ...

  6. Linux与Windows间使用git

    Linux与Windows间使用git Linux上架设git服务器,windows可以使用git从Linux上拉取/上传数据 windows使用工具:Git for Windows Linux上的用 ...

  7. [CSS] Conditionally Apply Styles Using Feature Queries @supports

    While browsers do a great job of ignoring styles they don’t understand, it can be useful to provide ...

  8. 一个自己主动依据xcode中的objective-c代码生成类关系图的神器

    https://github.com/kimsungwhee/KSHObjcUML 安装方法: 1.下载项目 2.执行 3.会又一次开启一个新的xcode 4.选择一个项目,点击 Objc-UML 会 ...

  9. LinearLayout的一些注意事项 分类: H1_ANDROID 2013-10-26 23:01 856人阅读 评论(0) 收藏

    1.orientation的默认值为horizontal,即从左向右排列.由于一般从上向下排列,所以必须指定orientation属性. 2.layout_gravity与gravity的区别: (1 ...

  10. js中单引号和双引号的区别(html中属性规范是用双引号,js中字符串规定是用单引号)(js中单引号区别和php很像:单引号快,双引号可转义字符,双引号可解析变量)

    js中单引号和双引号的区别(html中属性规范是用双引号,js中字符串规定是用单引号)(js中单引号区别和php很像:单引号快,双引号可转义字符,双引号可解析变量) 一.总结 1.html中属性规范是 ...