在开发当中经常会碰到需要进行行列转换及递归的问题:该类问题主要涉及的数据表现形式是
树形结构的数据,诸如机构组织、人事职位等。
1、递归
语法:递归表达式也称为CTE 公用表表达式,其形式如下:
-----------------------------------------------------------
with 临时名字(字段列表) as (
select 语句 //该语句一般为初始化语句,初始化临时视图的
union all //该句基本都是需要的
递归select语句 //该句执行时会引用前面定义的临时表,然后递归查询,直到返回空结果
)
select语句 //该句从临时表中获取最终想要的结果
-----------------------------------------------------------
以上结构是最简单的with递归,更复杂的,可能with中有好几个临时视图。
应用举例:
********用递归查询来实现DB2的行列转换问题 ****
假设有这么一个表:
A B
1 a
2 b
1 c
1 d
3 e
3 f
查询的结果为:
1 a,c,d
2 b
3 e,f
那么DB2的写法是这样的:
WITH T1(A,B,NUM) AS
(
Select A,B,ROW_NUMBER() OVER(PARTITION BY A orDER BY ID) FROM T
),
T2(RA,RB,NUM) AS
(
Select A,CHAR(B,10),NUM FROM T1 Where NUM = 1
UNION ALL
Select T2.RA,RTRIM(T2.RB)||','||T1.B,T1.NUM FROM T1 , T2 Where T1.NUM = T2.NUM + 1 AND T1.A = T2.RA
)
Select
RA,RB FROM T2
Where
NUM = ( Select MAX(NUM) FROM T2 TEMP Where TEMP.RA = T2.RA)
orDER BY RA
2、行列转换
行列转换包括以下六种情况:
*列转行
*行转列
*多列转换成字符串
*多行转换成字符串
*字符串转换成多列
*字符串转换成多行
分类:
1、固定列数的行列转换
student subject grade
--------- ---------- --------
student1 语文 80
student1 数学 70
student1 英语 60
student2 语文 90
student2 数学 80
student2 英语 100
……
转换为
语文 数学 英语
student1 80 70 60
student2 90 80 100
……
语句如下(oracle):select student,
sum(decode(subject,'语文', grade,null)) "语文",
sum(decode(subject,'数学', grade,null)) "数学",
sum(decode(subject,'英语', grade,null)) "英语"
from table
group by student;
2、不定列行列转换
c1 c2
--- -----------
1 我
1 是
1 谁
2 知
2 道
3 不
……
转换为
1 我是谁
2 知道
3 不
3、列数不固定(交叉表行列转置),如按日期统计销售情况
原始数据:
CLASS1 CALLDATE CALLCOUNT
1 2005-08-08 40
1 2005-08-07 6
2 2005-08-08 77
3 2005-08-09 33
3 2005-08-08 9
3 2005-08-07 21
转置后:
CALLDATE CallCount1 CallCount2 CallCount3
------------ ---------- ---------- ----------
2005-08-09 0 0 33
2005-08-08 40 77 9
2005-08-07 6 0 21
=====================
下面给出db2中行与列的互转实例:
行转列
给出下面的数据:
CREATE TABLE Sales (Year INT, Quarter INT, Results INT)
YEAR QUARTER RESULTS ----------- ----------- ----------- 2004 1 20 2004 2 30 2004 3 15 2004 4 10 2005 1 18 2005 2 40 2005 3 12 2005 4 27 想要的到结果: YEAR Q1 Q2 Q3 Q4 ----------- ----------- ----------- ----------- ----------- 2004 20 30 15 10 2005 18 40 12 27 这个SQL就可解决这个问题: SELECT Year, MAX(CASE WHEN Quarter = 1 THEN Results END) AS Q1, MAX(CASE WHEN Quarter = 2 THEN Results END) AS Q2, MAX(CASE WHEN Quarter = 3 THEN Results END) AS Q3, MAX(CASE WHEN Quarter = 4 THEN Results END) AS Q4 FROM Sales GROUP BY Year
利用max原因,因为不加max的话结果会是这样: YEAR Q1 Q2 Q3 Q4 ----------- ----------- ----------- ----------- ----------- 2004 20 - - - 2004 - 30 - - 2004 - - 15 - 2004 - - - 10 2005 18 - - - 2005 - 40 - - 2005 - - 12 - 2005 - - - 27
列转行
给出下面数据
CREATE TABLE SalesAgg ( year INTEGER, q1 INTEGER, q2 INTEGER, q3 INTEGER, q4 INTEGER ); YEAR Q1 Q2 Q3 Q4 ----------- ----------- ----------- ----------- ----------- 2004 20 30 15 10 2005 18 40 12 27 想要的结果 YEAR QUARTER RESULTS ----------- ----------- ----------- 2004 1 20 2004 2 30 2004 3 15 2004 4 10 2005 1 18 2005 2 40 2005 3 12 2005 4 27
这个SQL就可以实现:
SELECT S.Year, Q.Quarter, Q.Results FROM SalesAgg AS S, TABLE (VALUES(1, S.q1), (2, S.q2), (3, S.q3), (4, S.q4)) AS Q(Quarter, Results);
下面解释一下执行的过程: 核心是用table函数创建了一个表,这个表是用value实现的多行表,value实现虚表的例子: db2 => select * from (values (1,2),(2,3)) as t1(col1,col2) COL1 COL2 ----------- ----------- 1 2 2 3