简化实现动态行列转置的SQL

动态行列转换的计算在实际业务中非经常见,网上各类技术论坛上都有讨论,比方以下这些问题:

http://www.iteye.com/problems/87788

http://bbs.csdn.net/topics/390869577

http://bbs.csdn.net/topics/391000711

http://bbs.csdn.net/topics/391001035

http://bbs.csdn.net/topics/390888703

http://bbs.csdn.net/topics/391012377

http://bbs.csdn.net/topics/390956910

http://bbs.csdn.net/topics/391004719

http://bbs.csdn.net/topics/390946260

http://bbs.csdn.net/topics/390937222?page=1#post-398564938

http://bbs.csdn.net/topics/390883416

http://bbs.csdn.net/topics/390960953

http://bbs.csdn.net/topics/390959646

行转列使用SQL完毕一般有下面几种方法:

        1、 使用行列转换函数

Oracle11g及以上和MSSQL2005+提供了行列转置运算符pivot和unpivot,前者用于行转列,后者用于列转行。使用时须要指定目标列,对于动态列的场景无法直接完毕。

        2、 使用CASE表达式

对于不支持pivot的数据库。如Mysql、DB2。能够使用case when条件表达式完毕。与pivot类似,须要依据目标列固定写死,无法直接写出动态列结构转换。

对于动态列的情况。仅仅能:

        3、 拼接动态SQL

处理动态行列转换时往往须要在存储过程中拼接动态SQL完毕,因为数据库间的差异,写法与难易程度也不尽同样。无法编写通用的SQL语句。

实际情况中中,行列转换往往还伴随列间计算。增大了转置时的难度。

行列转换的目的经常是为了进一步的数据呈现。也就是说会有个主程序(如报表工具等)接受结果以进行下一步操作。假设是Java主程序,则能够使用润乾集算器(免费版)来协助完毕这类转换。集算器是动态解释运行的脚本。完毕行列转换的代码更具通用性。

集算器提供了JDBC接口,能够置于Java应用程序与数据库之间。让应用程序继续象訪问数据库一样运行集算器脚本,不用改变应用结构。

以下以一个简单的样例说明用集算器怎样实现行列转换。并集成进Java主程序中。

1、简单的行转列

一般的行转列仅仅简单地将数据行转为结果列。不涉及复杂的列间计算。

如将以下的学生成绩表转为分科目展示的集合:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

目标结果:

实现脚本:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

A1:运行SQL取数,并按ID、SUBJECT排序;

A2-A3:按ID和SUBJECT分组,集算器保留了分组后的子集供后面计算使用;

A4:动态创建空的目标结果集;

A5-B5:循环A2的学生分组,依据SUBJECT分组将学生ID、姓名和各科目成绩写入结果集;

A6:返回结果集。

从上面代码能够看出採用集算器实现行转列的基本步骤:先动态计算出空的目标结果集(A4)。再计算出每行数据追加到结果集中(A5,B5)。在有了支持数据表对象的分步计算机制后,行转列的过程能够按自然思路编写出来。

集算脚本的计算结果能够用JDBC接口返回给JAVA主程序或报表工具,JAVA调用集算脚本代码:

Class.forName("com.esproc.jdbc.InternalDriver");

con=DriverManager.getConnection("jdbc:esproc:local://");

//调用集算器脚本(类似存储过程),当中p1是集算器脚本文件名称

st=(com. esproc.jdbc.InternalCStatement)con.prepareCall("call p1 ()");

//运行脚本

st.execute();

//获取结果集

ResultSetrs = st.getResultSet();

……

返回值是符合JDBC标准的ResultSet对象,调用集算器脚本和訪问数据库的方法全然一样,熟悉JDBC的程序猿能够非常快掌握。

关于集算器JDBC的部署和调用的更具体信息可參考【集算器集成应用之被JAVA调用】。

        2、不定长分组的行转列

上一个样例中,结果集的列(即科目)常常能够事先获知,这样用静态的pivot(或case when)语法写出来也不算非常困难。但假设结果集的列须要动态计算出来,用pivot就非常困难了。如本例中每类机制生产的产品列数不定:

要求依据最大的机组分组长度决定转换后的结果列数。目标结果:



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

实现脚本:

A1:运行sql从产量表中取数;

A2:按机组分组。在集算器中分组结果保留了分组结果(成员)以方便兴许使用和计算;

A3:求分组中最大成员个数,以确定结果集列数;

A4-A5:动态创建空结果集;

A6-B7:循环A2中分组结果。将每一个分组中的类别和产量写入A5结果序表中。

与上述类似。这段代码仍然是先动态生成空结果集。然后再计算出合适的数据追加。

本例的计算须要写出动态的SQL来拼出结果集,但因为要找出最大的组才知道列数。拼结果也不是像一般的pivot那样能够用字段值直接相应成列。这就要写存储过程一步步地完毕才方便。

相对照较复杂的存储过程,集算脚本支持过程性计算,代码更加简洁、易编写。

        3、包括列间计算的行转列

如開始提到的,行列转换的同一时候往往伴随列间计算,比如有数据:

要求依据指定年份(如2014),输出每月应付金额,若无当月数据,则当月应付金额为上月该值。

目标结果:

实现脚本:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

A1:运行SQL取查询年数据;

A2:生成带有12个月的结果空序表;

A3:按客户分组;

A4-B7:循环分组。B5设置对应月份的应付金额。B6将空值置为前一个月的数值。B7将记录插入结果序表中。

运算过程仍然是先产生空结果集后追加数据,不同的是。这里要追加的数据须要常常一系列计算才干得到。

集算脚本支持有序运算。所以非常easy取到前一条记录的值。对于动态行列转换时发生的列间计算。与复杂SQL或存储过程相比。集算脚本更清晰易懂。

4、列转行

除了上述提到的转置,有时还有将一行多列数据转为多行数据(列转行)。例如以下数据,当中列数不定:

目标结果:



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

实现脚本:

A1:运行SQL取数;

A2:创建目标结果空序表;

A3:依据A1集合的列数计算每条记录要拆分的行数;

A4-B4:循环A1集合,动态获取每列数据插入A2结果序表中。

时间: 2024-10-05 13:47:04

简化实现动态行列转置的SQL的相关文章

sql server动态行列转换

原文链接:https://www.cnblogs.com/gaizai/p/3753296.html sql server动态行列转换 一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 方法一:使用拼接SQL,静态列字段: 方法二:使用拼接SQL,动态列字段: 方法三:使用PIVOT关系运算符,静态列字段: 方法四:使用PIVOT关系运算符,动态列字段: 扩展阅读一:参数化表名.分组列.行转列字段.字段值:

Excel 行列转置 解决竖向拉,字母跟着递增的问题

今天工作中遇到需要将Excel行列转置涉及到的数据单元格一共几千个 查询网上说可以通过复制粘贴单元格,粘贴选项中转置一项实现,但是所涉及的sheet页中,数据格式和单元格格式各不一样,转置失败! 怎么做呢? 先看看查询Excel函数的结果: 首先看看INDERECT函数的定义:返回字符串所指定的索引 比如: 有了这个函数,解决当前问题的思路就是在竖向拖动的时候,能对应到INDIRECT("A1"),INDIRECT("B1"),INDIRECT("C1&q

Oracle行列转置

两种简单的行列转置 1.固定列数的行列转换如student subject grade--------- ---------- --------student1 语文 80student1 数学 70student1 英语 60student2 语文 90student2 数学 80student2 英语 100--转换为 语文 数学 英语student1 80 70 60student2 90 80 100--语句如下: 1 select student, 2 sum(decode(subje

Excel-怎样实现行列转置

有时候,我们为了某些需要,必须把工作表的行列进行转置的方式显示.重新输入很浪费时间,怎样简单的实现转置呢,强大的excel2007提供了此项功能,具体怎么做,下面看我来演示一下. 工具/原料 装有excel2007的电脑一台 步骤/方法 如图所示,选中要进行行列转置的单元格区域.   选择"开始"选项卡,在"剪贴板"组中单击"复制"图标. 步骤阅读   在工作表中选中目标粘贴区域的左上角单元格.如图所示.   单击"剪贴板"组

还在傻傻用Ctrl+C和Ctrl+V吗?这2个行列转置方法助你效率提80%!

Excel行转为列,列转为行的例子特别常见,以下这两个方法可以帮助你解决99%行列转置问题! 点击文章右上角给小编一个"关注"鼓励,谢谢您! 我们先来对比下面两张图片: 当下面表格的名字越来越多时,表格也就越来越来,查看也就越来越麻烦. 而下面这个表格显示看起来比较舒心,这也是我们平时制作表格的方式. 那么通过对比,我们知道哪个图片才是我们想要的.但是有时候别人发给我们的表格并不是我们想要的方式,而且数据量很大,这时该用什么方法变成我们想要的呢? 方法一:使用"选择性粘贴&q

SQL Server中行列转置方法

PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )AS P 完整语法: table_source PIVOT( 聚合函数(value_column) FOR pivot_column IN(<column_list>) ) UNPIVOT用于将列明转为列值(即列转行),在SQL Server 2000可以用UNION来实现 完整语法: table_sou

sql server多重行列转置的优化

将表1转化成表2: 表1 表2 得到表2的结果,需要经过多次pivot转换,再经union连接到一起,代码如下: 1 select id, type,sum([1]) [1],sum([2]) [2],sum([3]) [3],sum([4]) [4] from 2 ( 3 select 'a' as type, * from Table_1 4 pivot(sum(a) for p in([1],[2],[3],[4])) as a 5 union all 6 select 'b' as ty

SQL行列转置

--函数 alter function zh() returns table as return( select 科目,max(张三) as 张三,max(李四)as 李四 from( select '语文'as 科目,张三,李四 from stu2 pivot(max(语文)for 姓名 in (科目,张三,李四))as a union all select '数学'as 科目,张三,李四 from stu2 pivot(max(数学)for 姓名 in (科目,张三,李四))as a )as

简化多层分组关联计算的sql

在数据库应用开发中,我们经常需要面对复杂的SQL式计算,比如多层分组中的关联计算.由于SQL分组时必须同时汇总,并且不能进行对象式关联访问,因此处理这类问题会比较复杂,只能用窗口函数嵌套多层的子查询的高级技巧来实现.集算器支持真正的分组,直观的对象式关联访问,解决这类问题更加容易. 分组关联在实际业务中遇到的较多,比如http://forums.bit-tech.net/showthread.php?t=207052.下面以链接中的实际业务为蓝本设计一个更通用的例子,用来说明集算器实现分组关联的