自引用表SQL查询到行

时间:2014-10-17 00:16:57

标签: sql oracle

我有这个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的一次(此一个没有子项,因此必须显示在结果集中)第一个结果集。

任何帮助将不胜感激。

2 个答案:

答案 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;