SQL的的行列倒置已经不是新知识了,但在博主的技术咨询期间,仍发现其实有很多人并不了解这块,所以在此专门写一篇博客记录。本文将以Mysql为例,并以数据采集指标信息获取为例子。在下面的例子,你可以在sqlfiddle运行。

首先我们需要创建数据库Schema:

    CREATE TABLE Chart
(`createTime` DateTime, `kpi` varchar(30), `field` varchar(30), `value` double); INSERT INTO Chart
(`createTime`,`kpi`, `field`, `value`)
VALUES
("2015-02-01 12:00:00", 'disk', 'disk', 20),
("2015-02-01 12:15:00", 'disk', 'disk', 30),
("2015-02-01 12:20:00", 'disk', 'disk', 25),
("2015-02-01 12:30:00", 'disk', 'disk', 25),
("2015-02-01 12:35:00", 'disk', 'disk', 25),
("2015-02-01 12:40:00", 'disk', 'disk', 25), ("2015-02-01 12:00:00", 'disk', 'disk-all', 20),
("2015-02-01 12:20:00", 'disk', 'disk-all', 30),
("2015-02-01 12:25:00", 'disk', 'disk-all', 25),
("2015-02-01 12:30:00", 'disk', 'disk-all', 25),
("2015-02-01 12:35:00", 'disk', 'disk-all', 25),
("2015-02-01 12:40:00", 'disk', 'disk-all', 25),
("2015-02-01 12:40:00", 'cpu', 'cpu-all', 25),
("2015-02-01 12:40:00", 'cpu', 'cpu', 25)
;

在这里字段分别代表:createTime = 数据采集时间,kpi = 数据采集指标,field = 作为指标的小类(一个kpi可以包含多个field),value = 采集的数据

当我们创建好了数据结构,下面因为我们希望获取出所有的 固定时间范围内的特定kpi的数据,注意因为可能一个kpi中的多个field,但是某些field漏采了部分时间的数据,所以这里我们需要补充异常点0. 并由于EChart这类图表库,希望我们输入的是横轴和纵轴为两个独立的数组对象表示。所以我们需要如下:

option = {
.... xAxis : [
{
type : 'category',
boundaryGap : false,
data : ['周一','周二','周三','周四','周五','周六','周日']
}
],
yAxis : [
{
type : 'value',
axisLabel : {
formatter: '{value} °C'
}
}
],
series : [
{
....
data:[11, 11, 15, 13, 12, 13, 10]
},
{
....
data:[11, 11, 15, 13, 12, 13, 10]
}
]
};

取出横轴比较容易,如下:

SELECT createTime,kpi, field, value FROM Chart WHERE kpi = 'disk' and (createTime BETWEEN '2015-02-01 12:00:00' AND '2015-02-01 12:25:00');

但是纵轴如果我们以同样方式取出,可能存在需要我们自动程序补值,并且需要保证每项数据和横轴对应,所以我们的程序处理会比较复杂,如下:

SELECT createTime,kpi, field, value FROM Chart WHERE kpi = 'disk' and (createTime BETWEEN '2015-02-01 12:00:00' AND '2015-02-01 12:25:00');

结果为:

createTime  kpi field   value
February, 01 2015 12:00:00 disk disk 20
February, 01 2015 12:15:00 disk disk 30
February, 01 2015 12:20:00 disk disk 25
February, 01 2015 12:00:00 disk disk-all 20
February, 01 2015 12:20:00 disk disk-all 30
February, 01 2015 12:25:00 disk disk-all 25

有没有其他方案更佳的呢?当然那就是本文要说的sql的倒置,如果我们能够把返回数据转换为如下:

field   ‘2015-02-01 12:00:00’   ‘2015-02-01 12:15:00’   ‘2015-02-01 12:20:00’   ‘2015-02-01 12:25:00’
disk 20 30 25 0
disk-all 20 0 30 25

那么程序就很好处理了。在上面我们已经能够取出所有的横轴数据并排序,接下来我们将可以很简单的做到行列倒置:如下:

SELECT field,
SUM(IF(createTime = '2015-02-01 12:00:00', value, 0)) as '2015-02-01 12:00:00',
SUM(IF(createTime = '2015-02-01 12:15:00', value, 0)) as '2015-02-01 12:15:00',
SUM(IF(createTime = '2015-02-01 12:20:00', value, 0)) as '2015-02-01 12:20:00',
SUM(IF(createTime = '2015-02-01 12:25:00', value, 0)) as '2015-02-01 12:25:00'
FROM Chart
WHERE kpi = 'disk' and (createTime BETWEEN '2015-02-01 12:00:00' AND '2015-02-01 12:25:00')
GROUP BY field

这样返回数据满足我们的需求了。


下面我们来分析下这句SQL,

  1. 首先我们利用‘IF(createTime = ‘2015-02-01 12:00:00’, value, 0)’来处理插值,并对每行数据转为以时间为列数据,并可以利用IF来补’0‘,将会如下:

SQL:

SELECT field,
IF(createTime = '2015-02-01 12:00:00', value, 0) as '2015-02-01 12:00:00',
IF(createTime = '2015-02-01 12:15:00', value, 0) as '2015-02-01 12:15:00',
IF(createTime = '2015-02-01 12:20:00', value, 0) as '2015-02-01 12:20:00',
IF(createTime = '2015-02-01 12:25:00', value, 0) as '2015-02-01 12:25:00'
FROM Chart
WHERE kpi = 'disk' and (createTime BETWEEN '2015-02-01 12:00:00' AND '2015-02-01 12:25:00');

结果为:

field   ‘2015-02-01 12:00:00’   ‘2015-02-01 12:15:00’   ‘2015-02-01 12:20:00’   ‘2015-02-01 12:25:00’
disk 20 0 0 0
disk 0 30 0 0
disk 0 0 25 0
disk-all 20 0 0 0
disk-all 0 0 30 0
disk-all 0 0 0 25
  1. 这下我们就可以利用sql的聚合函数sum和group by来聚合数据行:

SQL:

SELECT field,
SUM(IF(createTime = '2015-02-01 12:00:00', value, 0)) as '2015-02-01 12:00:00',
SUM(IF(createTime = '2015-02-01 12:15:00', value, 0)) as '2015-02-01 12:15:00',
SUM(IF(createTime = '2015-02-01 12:20:00', value, 0)) as '2015-02-01 12:20:00',
SUM(IF(createTime = '2015-02-01 12:25:00', value, 0)) as '2015-02-01 12:25:00'
FROM Chart
WHERE kpi = 'disk' and (createTime BETWEEN '2015-02-01 12:00:00' AND '2015-02-01 12:25:00')
GROUP BY field

效果如上。

对于sql行列转置可以简述为分为两部分:

  1. 利用条件逻辑(mysql: IF, sql server: case … when(sql server 2005开始支持数据透视表pivot) ..)将 需要倒置的数据变为列。
  2. 利用聚合函数(sum、max、min…)group by 合并数据。这里需要注意max、min需要注意数据的边界,如存在负数且默认值采用0,那么max就会存在问题,所以一般sum是最安全的(任何数加0都不会改变结果);但对于特定场景max、min也是安全方案。

我们也可以将上面两次请求合并为一次,这就需要mysql的动态拼接,如下:

SELECT
@time_sql := group_concat("SUM(IF(createTime = '", t.createTime, "', value, 0)) AS '" , t.createTime, "'")
FROM (
SELECT DISTINCT createTime FROM Chart ORDER BY createTime
) AS t; set @v_sql = CONCAT("SELECT field", IF(ISNULL(@time_sql) , " ", CONCAT(", ", @time_sql)) ," FROM Chart GROUP BY field"); prepare stmt from @v_sql;
EXECUTE stmt;
deallocate prepare stmt;

SQL 行列倒置的更多相关文章

  1. SQL行列转换6种方法

    在进行报表开发时,很多时候会遇到行列转换操作,很对开发人员针对于SQL级别行列转换操作一直不甚理解,今天正好抽空对其进行了一些简单的总结.这里主要列举3种可以实现SQL行列转换的方法,包括通用SQL解 ...

  2. SQL行列乾坤大挪移

    “生活总是这样,有时候,你需要一个苹果,但别人却给了你一个梨.” 今天dalao邮件里需要添加一张每月累计长长的图,可是,拿到手上的SQL导出数据不符合我最爱的pyecharts的数据输入格式,头大. ...

  3. 数据透视表sql:用SQL行列转换实现数据透视的一些思考

    用SQL行列转换实现数据透视的一些思考 摘要:根据对报表开发过程中碰到的需要用SQL行列转换进行解决的一类查询统计问题的分析,逐步探索求解得到一种较通用的解决思路,并用函数进行实现.该解决思路及函数实 ...

  4. sql行列旋转

    一,行转列 先建立测试数据 if OBJECT_ID('week_income') is not null drop table week_income go create table week_in ...

  5. sql行列转换

    首先我们建立一张表,名为scoreInfo,各个字段的设计如下图,分别是name,course,score,表示姓名,成绩与分数,如图所示.

  6. mysql:sql行列转换

    今天一个同学遇到一个问题问我了,由于本人平时学习的mysql比较基础,确实没解决,后来google了一下,才知道是sql的一种技法[行列转换],话不多说先上图: 想得到下面的结果: +------+- ...

  7. SQL行列转换:报表_公司采购表_每个公司各采购了些什么产品

    有同学问了个比较典型行列转换的问题,想想,解答如下:数据库有一张表: 是个公司采购表,想转化成如下报表,显示每个公司各采购了些什么产品: 哪些公司采购哪些产品是不确定的,所以报表的列有哪几项是不确定的 ...

  8. SQL行列轉換方法(詳細例子)

    普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法. 问题:假设有张学生成绩表(tb)如下 ...

  9. 绝妙的SQL行列转换语句

      说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法. 问题:假设有张学生成绩表( ...

随机推荐

  1. DBCC SHOWCONTIG、DBCC DBREINDEX。

    use dbname declare @table_id int set @table_id=object_id('tablename') dbcc showcontig(@table_id) 解释如 ...

  2. 在Xcode中使用Git进行源码版本控制

    http://www.cocoachina.com/ios/20140524/8536.html 资讯 论坛 代码 工具 招聘 CVP 外快 博客new 登录| 注册   iOS开发 Swift Ap ...

  3. MG--滚动的视觉差效果

    #几句代码完成tableView滚动的视觉差 - 效果图 (失帧严重)![](http://upload-images.jianshu.io/upload_images/1429890-f2c8577 ...

  4. 关于Linux的 /sbin权限问题

    安装ubuntu一段时间后新增了用户,突然发现原来的用户用不了 ifconfig ,提示找不到命令 一试之下发现/sbin/ifconfig,可以,明白了是因为用户新增了,系统不认为当前用户是唯一用户 ...

  5. Linux下Bash入门学习笔记

    学习好shell编程是很有用的,可以使用shell脚本轻巧地完成有趣的工作. 本文地址:http://www.cnblogs.com/yhLinux/p/4047516.html 1. Bash实例, ...

  6. step by step 之餐饮管理系统七(点菜模块实现)

    好长时间没有更新这个系列了,一是因为这段时间比较忙,有很多事情,二来要学习新的东西,AngularJs,devExpress这两上框架,都是比较有名的框架,先上图: 上面就是用来点菜的界面,左边是已点 ...

  7. install mysql using binary and configure manu

    (1)下载,解压 (2)初始化数据库 ./scripts/mysql_install_db --defaults-file=../my.cnf --user=guofeng (3)启动命令 ./bin ...

  8. LinqToEntity模糊查询的方法选择

    LinqToEntity针对oracle模糊查询 方法:Contains() 转换出来的sql是  like  关键字 方法:IndexOf()  转换出来的sql是  instr()  函数 lik ...

  9. WCF android调用

    http://www.cnblogs.com/cg6811568/archive/2013/05/23/3095119.html

  10. js继承理解(有引用)

    具体栗子:http://www.cnblogs.com/ayqy/p/4471638.html(地下为自己理解总结,可能晦涩,链接详细) 1.父类实例赋予子类原型. 2.利用子类函数引用 父类.cal ...