注:本文使用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.什么是事务 事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求.要么都执行 ...
随机推荐
- LA 3602 - DNA Consensus String 枚举
原题地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- self.view.layer.contents 和 self.view.backgroundColor
一. self.view.layer.contents 和 self.view.backgroundColor 今天测了一下 : self.view.layer.contents 和 self. ...
- PHP Filesystem 函数(文件系统函数)(每日一课的内容可以从php参考手册上面来)
PHP Filesystem 函数(文件系统函数)(每日一课的内容可以从php参考手册上面来) 一.总结 1.文件路径中的正反斜杠:当在 Unix 平台上规定路径时,正斜杠 (/) 用作目录分隔符.而 ...
- [Docker] Build a Simple Node.js Web Server with Docker
Learn how to build a simple Node.js web server with Docker. In this lesson, we'll create a Dockerfil ...
- 自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法
前言:这几天做客户回访,感触很大,用户只要是留反馈信息,总是一种恨铁不成钢的心态,想用你的app,却是因为你的技术问题,让他们不得不放弃,而你一个回访电话却让他们尽释前嫌,当最后把手机号留给他们以便随 ...
- Thinking in UML 学习笔记(二)——UML核心视图之用例图
在UML中,需求模型又称为用例模型,它主要用于描述系统的功能性需求,即软件可以实现的功能,如登录.注册.入库.出库.查看库存报表.增加员工信息等.常规的用例建模一般包括两个组成部分:绘制用例图和编写用 ...
- PatentTips - Integrated circuit well bias circuitry
1. Field of the Invention This invention relates in general to an integrated circuit and more specif ...
- [网络管理]windows server backup
ERPserver每天备份与每月1号备份数据.备份到本机.从备份安全机制来说这是远远不够的.故是否能定期备份数据文件到另外一台server呢?(异地备份) windows server 提供了serv ...
- [NPM] List available npm scripts and support tab completion
In this lesson we will look at different ways you can list the available npm scripts. Whether we wan ...
- Qt 通过绘画设置边框阴影
首先widget设置 setWindowFlags(Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground, true) ...