需求:
课程表: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
方法2:10G 中的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(未同步) |