1、纵表与横表

纵表:表中字段与字段的值采用key—value形式,即表中定义两个字段,其中一个字段里存放的是字段名称,另一个字段中存放的是这个字段名称代表的字段的值。

例如,下面这张ats_item_record表,其中field_code表示字段,后面的record_value表示这个字段的值

优缺点:

横表:表结构更加的清晰明了,关联查询的一些sql语句也更容易,方便易于后续开发人员的接手,但是如果字段不够,需要新增字段,会改动表结构。

纵表:扩展性更高,如果要增加一个字段,不需要改变表结构,但是一些关联查询会更加麻烦,也不便于维护与后续人员接手。

平常开发,尽量能用横表就不要用纵表,维护成本比较高昂,而且一些关联查询也很麻烦。

2、纵表转换为横表

(1)第一步,我们先把这些字段名以及相应字段的值从纵表中取出来

select r.original_record_id,r.did,r.device_sn,r.mac_address,r.record_time, r.updated_time updated_time,
(case r.field_code when 'accumulated_cooking_time' then r.record_value else '' end ) accumulated_cooking_time,
(case r.field_code when 'data_version' then r.record_value else '' end) data_version,
(case r.field_code when 'loop_num' then r.record_value else '' end) loop_num,
(case r.field_code when 'status' then r.record_value else '' end) status
from ats_item_record r
where item_code = 'GONGMO_AGING'

结果:

通过 case 语句,成功把字段从纵表中取出,但是此时仍算不上一个横表,我们这里的original_record_id 是记录同一行数据的唯一ID,我们这里可以通过这个字段把上面这四行合成一行记录。

注意:这里需要取出每一个字段,都要case一下,有多少个字段,就需要多少次case语句。因为一个case语句,遇到符合条件的when语句之后,后面的会不再执行。

(2)分组,合并相同行,生成横表

select * from (select r.original_record_id,max(r.did) did,max(r.device_sn) device_sn,max(r.mac_address) mac_address,max(r.record_time) record_time,max(r.updated_time) updated_time,max((case r.field_code when 'accumulated_cooking_time' then r.record_value else '' end )) accumulated_cooking_time,max((case r.field_code when 'data_version' then r.record_value else '' end)) data_version,max((case r.field_code when 'loop_num' then r.record_value else '' end)) loop_num,max((case r.field_code when 'status' then r.record_value else '' end)) statusfrom ats_item_record r where item_code = 'GONGMO_AGING'group by r.original_record_id
) m order by m.updated_time desc;

查询的结果:

注意:这里采用group by 分组的时候,需要给字段加上max函数。用group by 分组的时候,一般搭配聚合函数使用,常见的聚合函数:

  • AVG() 求平均数
  • COUNT() 求列的总数
  • MAX() 求最大值
  • MIN() 求最小值
  • SUM() 求和

大家注意一下,我把纵表同一条记录的公共字段 r.original_record_id 放到了group by里面,这个字段在纵表中同一条记录相同、唯一,且永远不会改变(相当于以前横表的主键ID),然后把其他字段放到 max 中(因为其他字段要么是相同的,要么是取最大的就可以,要么是只有一个纵表记录有数值其他记录为空,所以这三种情况都可以直接用max),四条记录取最大的更新时间作为同一条记录的更新时间,在逻辑上也是合适的。然后我们把纵表字段 field_code 和 record_value 做了 max() 操作,因为同一条记录里面他们都是唯一存在的,不会发生同一条数据有两个相同的 field_code 记录,所以这样做 max() 也是没有任何问题的。

优化点:

最后这个SQL是可以优化一下的,我们可以把模板字段(r.original_record_id,r.did,r.device_sn,r.mac_address,r.record_time 等),从专门存放模板字段表中全部取出来(同一个逻辑纵表的字段全部取出),然后再代码里面拼接好我们的 max() 部分,作为参数拼接进去执行,这样可以做到通用,每次如果新增加模板字段,我们不需要更改这个SQL语句了(中国移动他们存放手机的参数数据就是这么干的)。

优化后的业务层(组装 SQL 模板的代码),代码如下:

@Override
public PageInfo<AtsAgingItemRecordVo> getAgingItemList(AtsItemRecordQo qo) {//1、获取工模老化字段模板LambdaQueryWrapper<AtsItemFieldPo> queryWrapper = Wrappers.lambdaQuery();queryWrapper.eq(AtsItemFieldPo::getItemCode, AtsItemCodeConstant.GONGMO_AGING.getCode());List<AtsItemFieldPo> fieldPoList = atsItemFieldDao.selectList(queryWrapper);//2、组装查询条件List<String> tplList = Lists.newArrayList(), conditionList = Lists.newArrayList(), validList = Lists.newArrayList();if (!CollectionUtils.isEmpty(fieldPoList)) {//3、组装动态max查询字段for (AtsItemFieldPo itemFieldPo : fieldPoList) {tplList.add("max((case r.field_code when '" + itemFieldPo.getFieldCode() + "' then r.record_value else '' end )) " + itemFieldPo.getFieldCode());validList.add(itemFieldPo.getFieldCode());}qo.setTplList(tplList);//4、组装动态where查询条件if (StringUtils.isNotBlank(qo.getDid())) {conditionList.add("AND did like CONCAT('%'," + qo.getDid() + ",'%')");}if (validList.contains("batch_code") && StringUtils.isNotBlank(qo.getBatchCode())) {conditionList.add("AND batch_code like CONCAT('%'," + qo.getBatchCode() + ",'%')");}qo.setConditionList(conditionList);}qo.setItemCode(AtsItemCodeConstant.GONGMO_AGING.getCode());//4、获取老化自动化测试项记录PageHelper.startPage(qo.getPageNo(), qo.getPageSize());List<Map<String, Object>> dataList = atsItemRecordDao.selectItemRecordListByCondition(qo);PageInfo pageInfo = new PageInfo(dataList);//5、组装返回结果List<AtsAgingItemRecordVo> recordVoList = null;if (!CollectionUtils.isEmpty(dataList)) {recordVoList = JSONUtils.copy(dataList, AtsAgingItemRecordVo.class);}pageInfo.setList(recordVoList);return pageInfo;
}

优化后的Dao层,代码如下:

public interface AtsItemRecordDao extends BaseMapper<AtsItemRecordPo> {List<Map<String, Object>> selectItemRecordListByCondition(AtsItemRecordQo qo);
}

优化后的SQL语句,代码如下:

<select id="selectItemRecordListByCondition" resultType="java.util.HashMap"parameterType="com.galanz.iot.ops.restapi.model.qo.AtsItemRecordQo">SELECT * FROM (SELECT r.original_record_id id,max(r.did) did,max(r.device_sn) device_sn,max(r.updated_time) updated_time,max(r.record_time) record_time,<if test="tplList != null and tplList.size() > 0"><foreach collection="tplList" item="tpl" index="index" separator=",">${tpl}</foreach></if>FROM ats_item_record rWHERE item_code = #{itemCode}GROUP BY r.original_record_id) m<where><if test="conditionList != null and conditionList.size() > 0"><foreach collection="conditionList" item="condition" index="index">${condition}</foreach></if></where>ORDER BY m.updated_time DESC
</select>

模板字段表结构(ats_item_field 表),如下所示:

字段名 类型 长度 注释
id bigint 20 主键ID
field_code varchar 32 字段编码
field_name varchar 32 字段名称
remark varchar 512 备注
created_by bigint 20 创建人ID
created_time datetime 0 创建时间
updated_by bigint 20 更新人ID
updated_time datetime 0 更新时间

记录表结构(ats_item_record 表),如下所示:

字段名 类型 长度 注释
id bigint 20 主键ID
did varchar 64 设备唯一ID
device_sn varchar 32 设备sn
mac_address varchar 32 设备Mac地址
field_code varchar 32 字段编码
original_record_id varchar 64 原始记录ID
record_value varchar 32 记录值
created_by bigint 20 创建人ID
created_time datetime 0 创建时间
updated_by bigint 20 更新人ID
updated_time datetime 0 更新时间

注:original_record_id 是纵转横表后,每条记录的唯一ID,可以看做我们普通横表的主键ID一样的东西

到此 Mysql 纵表转换为横表介绍完成。

Mysql 纵表转换为横表相关推荐

  1. 关于竖表转横表的问题

    本文作者:dinya 内容摘要:在开发过程,经常遇到一些将表的显示方式进行转换的需求,我们习惯性称之为竖表到横表的转换,本文通过一个例子来简要说明常见的两种竖表转横表的问题. 本文适宜读者范围:ora ...

  2. MySQL中竖表和横表之间的相互转换

    MySQL中竖表和横表之间的相互转换 1.  横表转为竖表 表tb的结构为 表中的数据为 现在要求查询到如下结果 使用的SQL查询语句应该如下: 或者使用下面查询 2.  竖表转为横表 tb2表的结构 ...

  3. mysql把结果变横表_mysql纵表与横表转换实例

    1.纵表转横表: 纵表结构:Table1 转换后的横表结构: Sql示例代码: 2.横表转纵表: 横表结构: TableA ID      姓名    语文        数学       英语 1  ...

  4. oracle使用decode实现竖表转横表 (列转行)

    工作中时长会用到竖表转横表(列转行)例如某商场每天都有营业额,数据库中营业额存储的方式是每天很多比每笔对应不同的消费记录 ,可能有一天的营业额很多 对应的营业额明细就会很多,如果有个需求是要统计每天营 ...

  5. 纵表、横表互转的SQL

    纵表.横表互转的SQL By:大志若愚 1.建表: 纵表结构 Table_A  create table Table_A (姓名 varchar(20),课程 varchar(20),成绩 int ) ...

  6. Oracle实现竖表转横表的几种常用方法(行转列)

    有能耗表,记录各个城市水.电.热的能耗情况,表结构如下: 表结构 名称 类型 备注 E_CODE VARCHAR2(10) 城市的CODE E_VALUE NUMBER 能耗值,包括水耗.电耗.热耗 ...

  7. HIVE中纵表转横表

    最近在写hive脚本的时候,遇到一个问题就是,现在存在一个纵表(详细表),如下所示 table T1 id bankname cardname 1 中国银行 金卡 2 中国银行 白金卡 3 建设银行 ...

  8. oracle max decode竖表改横表

    1.oracle :max+decode 竖表改横表 展示为 select a.project_id,        max(decode(a.vote_result, '01', a.zaiyi, ...

  9. SQL中纵表、横表互相转换

    1.建表: 纵表结构 Table_A  create table Table_A (姓名 varchar(20),课程 varchar(20),成绩 int ) insert into Table_A ...

  10. mysql+纵表和横表_mysql 横表和纵表转换

    (1)表tb1有如下数据: 姓名                     语文                        数学                    物理 张三           ...

最新文章

  1. linux 循环shell脚本,shell脚本的使用---for循环
  2. 营销网站SEO优化:前方优化难点出没!
  3. 裸机篇 -- S5PV210的中断体系
  4. windows 下 logstash 安装启动
  5. 野生前端的数据结构练习(11)动态规划算法
  6. 互联网核心应用(搜索/推荐/广告)算法峰会
  7. php--------使用js生成二维码
  8. Tests for normality正态分布检验
  9. 所谓的开发是java还是PLC_SCL是否将成为PLC的主流编程语言?
  10. java三大特征_java三大特性是什么?
  11. SVN下载及其安装配置
  12. 怎么用真机测试android,andriod studio如何使用真机测试 andriod studio真机测试教程
  13. 第二章:minio单机版,使用客户端备份文件
  14. python_循环语句for_1.12
  15. AFM测试常见问题及解答(一)
  16. 我对ML和DL的看法
  17. JSP网上二手交易商城
  18. 朋友.心情父子.亲情
  19. 【漫漫长征路】hihocoder #1082 然而沼跃鱼早就看穿了一切
  20. 【菜鸡的自动化学习之旅】《电力电子技术》学习笔记1 ———— 电力电子器件

热门文章

  1. 中国工商银行客服经理校招面试
  2. udp buffer 和reassemble buffer
  3. win7局域网共享设置_win7局域网共享,教你在智能电视上看win7系统电脑资源
  4. css找某个元素的下个子元素,使用CSS获取特定位置的子元素
  5. Excel 冻结首行
  6. 移动设备管理与OMA DM 协议 V5(3)
  7. js根据年份计算总周数并获取每周的日期范围
  8. Chrome下面查看placeholder的样式
  9. 中国占三分之一!CBinsights世界最新独角兽排名出炉
  10. 最小二乘法简解及空间直线拟合