我有这个oracle 11g查询:
SELECT RPAD(' ', 2 * (T.ID_LEVEL - 1)) || T.IDE IDE, T.ID_LEVEL, T.CODE, T.FK_IDE
FROM TEST_DYNAMIC T
START WITH T.FK_IDE = 0
CONNECT BY NOCYCLE PRIOR T.IDE = T.FK_IDE
ORDER BY T.IDE,T.FK_IDE;
返回此数据:
IDE |IDE_LEVEL |CODE |FK_IDE |
-----|-----------|------|--------|
1 | 1|A01 | 0|
2 | 2|A01 | 1|
3 | 3|A01 | 2|
4| 4|A01 | 3|
5 | 2|A02 | 1|
6 | 2|A03 | 1|
7 | 3|A01 | 6|
8 | 1|A02 | 0|
如您所见,数据是从自我重新生成表中获取的,其中IDE_LEVEL列是主表的外键,其中包含此值(1,2,3,4)作为PK,IDE列为来自TEST_DYNAMIC表的自动增量PK。
有没有办法将结果转换为这个?:
IDE |CODE_LEVEL1 |CODE_LEVEL2 |CODE_LEVEL3 |CODE_LEVEL4 |
-----|-------------|-------------|-------------|-------------|
1 |A01 |A01 |A01 |A01 |
1 |A01 |A02 |NULL |NULL |
1 |A01 |A03 |A01 |NULL |
8 |A02 |NULL |NULL |NULL |
在上面的预期结果中,IDE列显示三次,对应于密钥1的FK_COLUMN中的三个事件,密钥8的一次(此一个没有子项,因此必须显示在结果集中)第一个结果集。
任何帮助将不胜感激。
答案 0 :(得分:0)
如果级别数是动态的,则无论如何都需要使用动态SQL来创建具有动态列的查询。
至少有两种方法可以创建这样的查询:
1)Oracle使用PIVOT(因为我认为是11g)
with test_dynamic as (
select 1 ide, 1 id_level, 'A01' code, 0 fk_ide from dual
union all select 2, 2, 'A01', 1 from dual
union all select 3, 3, 'A01', 2 from dual
union all select 4, 4, 'A01', 3 from dual
union all select 5, 2, 'A02', 1 from dual
union all select 6, 2, 'A03', 1 from dual
union all select 7, 3, 'A01', 6 from dual
union all select 8, 1, 'A02', 0 from dual
),
tree as (
select level lvl, t.ide, t.code
from test_dynamic t
start with t.fk_ide = 0
connect by nocycle prior t.ide = t.fk_ide
),
pivot_data as (
select * from tree pivot xml (max(code) lvl_code for lvl in (select distinct lvl from tree))
)
select ide,
extractvalue(lvl_xml,'/PivotSet/item[1]/column[2]') code_level1,
extractvalue(lvl_xml,'/PivotSet/item[2]/column[2]') code_level2,
extractvalue(lvl_xml,'/PivotSet/item[3]/column[2]') code_level3,
extractvalue(lvl_xml,'/PivotSet/item[4]/column[2]') code_level4
from pivot_data t order by 1;
(人们说EXTRACTVALUE可能会被弃用并建议使用XMLTABLE,但我从未使用过它)
2)Oracle DECODE
with test_dynamic as (
select 1 ide, 1 id_level, 'A01' code, 0 fk_ide from dual
union all select 2, 2, 'A01', 1 from dual
union all select 3, 3, 'A01', 2 from dual
union all select 4, 4, 'A01', 3 from dual
union all select 5, 2, 'A02', 1 from dual
union all select 6, 2, 'A03', 1 from dual
union all select 7, 3, 'A01', 6 from dual
union all select 8, 1, 'A02', 0 from dual
),
tree as (
select level lvl, t.ide, t.code
from test_dynamic t
start with t.fk_ide = 0
connect by nocycle prior t.ide = t.fk_ide
)
select ide,
max(decode(lvl, 1, code, null)) code_level1,
max(decode(lvl, 2, code, null)) code_level2,
max(decode(lvl, 3, code, null)) code_level3,
max(decode(lvl, 4, code, null)) code_level4
from tree group by ide order by 1;
答案 1 :(得分:0)
我一开始没有得到这个问题。您不需要PIVOT,您需要在单独的列中显示每个分支的路径。无论如何,根据你可能需要一些动态sql的级别数量
with test_dynamic as (
select 1 ide, 1 id_level, 'A01' code, 0 fk_ide from dual
union all select 2, 2, 'A01', 1 from dual
union all select 3, 3, 'A01', 2 from dual
union all select 4, 4, 'A01', 3 from dual
union all select 5, 2, 'A02', 1 from dual
union all select 6, 2, 'A03', 1 from dual
union all select 7, 3, 'A01', 6 from dual
union all select 8, 1, 'A02', 0 from dual
),
tree as (
select code, level lvl, sys_connect_by_path(code, '/') path, connect_by_isleaf lf, connect_by_root(ide) root_ide
from test_dynamic t
start with t.fk_ide = 0
connect by nocycle prior t.ide = t.fk_ide
)
select root_ide, path,
regexp_substr(path, '[^/]+', 1, 1),
regexp_substr(path, '[^/]+', 1, 2),
regexp_substr(path, '[^/]+', 1, 3),
regexp_substr(path, '[^/]+', 1, 4)
from tree where lf = 1;