西北狼

-- 学而时习之,不亦乐乎!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Oracel 行转列

Posted on 2011-06-05 03:20  西北老狼  阅读(323)  评论(0编辑  收藏  举报

需求:

课程表:tb_Course

CID

CN(Course Name)

1

C1

2

C2

 区域表:tb_Area

AID

AN

1

A1

2

A2

3

A3

4

A4

5

A5

 

区域国家表: tb_Area_Country

AID

AN(Area Name)

CoID (Country ID)

1

A1

1

1

A1

2

1

A1

3

2

A2

4

2

A2

5

2

A2

6

3

A3

7

4

A4

8

5

A5

9

课程到国家的同步状态 tb_record (没有记录的就是未同步)

CID(Course ID)

CoID(Country ID)

Status

 

 1

 1

1

 1:同步中,2:已同步

1

2

2

1

3

1

1

4

1

1

5

2

1

6

2

1

7

2

1

8

1

 

 

 

 

 

 

 

 

 

 

展示样例:

CID 

DistributeArea

(include tb_record.status is 2)

No_DistributeArea

(include tb_record.status is 0, 1)

1

A3(已同步)

A1(同步中)A2(同步中)A4(同步中)A5(未同步)

2

A1(未同步)A2(未同步)A2(未同步)A4(未同步)A5(未同步)

                                 

实现:

第一步:先关联 tb_Area tb_record 得到区域的同步状态AS以及区域分发状态AD

Select tbR.CID, tbA.AN, decode(min(tbR.status),‘1’, ‘同步中’, ‘已同步’) AS, decode(min(tbR.status), ‘2’, ‘1’, ‘0’) AD

From tb_Area_Country tbA join tb_record tbR on tbA.CoID = tbR.CoID

Group by tbR.CID, tbA.AN 结果表:T1

CID

AN

AS

AD

1

A1

同步中

0

1

A2

同步中

0

1

A3

已同步

1

1

A4

同步中

0

第二步:用课程表和区域表做迪卡积,除去同步中及已同步的记录,再与同步中,已同步的记录做union,得到所有记录

Select c.cid, a.AN, '未同步' AS, '0' AD

from tb_Course c cross join tb_area a

where not exists(select 1 from

(Select tbR.CID, tbA.AN, decode(min(tbR.status),’1’,’同步中’,’已同步’) AS,

                              decode(min(tbR.status), ‘2’, ‘1’, ‘0’) AD

                              From tb_Area_Country tbA join tb_record tbR on tbA.CoID = tbR.CoID

                              Group by tbR.CID, tbA.AN

                           ) t

                           Where t.cid = c.cid and t.AN = a.AN

                           )

union

Select tbR.CID, tbA.AN, decode(min(tbR.status),’1’,’同步中’,’已同步’) AS,

 decode(min(tbR.status), ‘2’, ‘1’, ‘0’) AD

From tb_Area_Country tbA join tb_record tbR on tbA.CoID = tbR.CoID

Group by tbR.CID, tbA.AN;

 

CID

AN

AS

AD

1

A1

同步中

0

1

A2

同步中

0

1

A3

已同步

1

1

A4

同步中

0

1

A5

未同步

0

2

A1

未同步

0

2

A2

未同步

0

2

A3

未同步

0

2

A4

未同步

0

2

A5

未同步

0

 

一二步可以合起来做,如果没有过滤条件可以用定义成视图,如果有查询条件就可以创建一个临时表,过滤后插入临时表。我们暂且定义为视图:T1.

 

第三步:思路是先构建一颗树,然后再将树转成列:

 

方法1:构建树,先设法构建父子关系表 T2

1、先给表排序获得行号作为父节点ID

Select T1.CID, T1.AN, T1.AS, T1.AD, row_number() over(order by T1.CID,T1.AD) rnFirst

From T1 得到T2

2、使用lead函数和分区特性得到子节点id

Select T2.CID, T2.AN, T2.AS, T2.AD, T2.rnFirst, lead(T2.rnFirst) over(partition by T2.CID,T2.AD order by T2.rnFirst) rnNext From T2 得到T3 

3、构造树,利用sys_connect_by_path函数链接字符串

Select T3.CID, T3.AD, sys_connect_by_path(T3.AN ||’(‘ || T3.AS || ‘)’, ‘’) Area

From T3

Start with T3.rnNext is Null

Connect by rnNext = prior rnFirst 得到T4

 

合成一个语句:

Select T3.CID, T3.AD, sys_connect_by_path(T3.AN ||’(‘ || T3.AS || ‘)’, ‘’) Area

From (Select T2.CID, T2.AN, T2.AS, T2.AD, T2.rnFirst, lead(T2.rnFirst) over(partition by T2.CID,T2.AD order by T2.rnFirst) rnNext

From (Select T1.CID, T1.AN, T1.AS, T1.AD, row_number() over(order by T1.CID,T1.AD) rnFirst

From T1

     ) T2

      ) T3

Start with T3.rnNext is Null

Connect by rnNext = prior rnFirst

 

 

方法210G 中的wmsys.wm_concat 方法 

Select T1.CID, T1.Ad, wmsys.wm_concat(T3.AN ||'('||t1.AS||')') over(partition by T1.CID, T1.AD order by rownum) Area

From T1 

 

构建树的结果也可以保存到一个临时表里。

 

第四步、分组取最大值:

Select T4.CID, T4.AD, ltrim(max(t4.Arear), ‘’) Area From T4 得到T5

CID

AD

Area

1

1

A3(已同步)

1

0

A1(同步中)A2(同步中)A4(同步中)A5(未同步)

2

0

A1(未同步)A2(未同步)A2(未同步)A4(未同步)A5(未同步)

 

第四步:行转列

Select T5.CID, max(decode(T5.AD, ‘1’, T5.Area, ‘’)) v1, max(decode(T5.AD, ‘0’, T5.Area, ‘’)) v2

From T5

Group by T5.CID

CID

V1

V2

1

A3(已同步)

A1(同步中)A2(同步中)A4(同步中)A5(未同步)

2

A1(未同步)A2(未同步)A2(未同步)A4(未同步)A5(未同步)