我有一个源表(T1):
ID1 | ID2
----------
1 | 2
1 | 5
4 | 7
7 | 8
9 | 1
我想将数据转换为此(T2):
ID1 | ID2 | LABEL
------------------
1 | 2 | 1
1 | 5 | 1
4 | 7 | 2
7 | 8 | 2
9 | 1 | 1
我在PostgreSQL中找到了一个解决方案:
with
recursive cte(id1, id2) as (
select id1, id2, 1 as level
from t
union all
select t.id1, cte.id2, cte.level + 1
from t join
cte
on t.id2 = cte.id1
)
select id1, id2,
dense_rank() over (order by grp) as label
from (select id1, id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
level
from cte
) t
where level = 1;
我想将此代码转换为Oracle。如何将此代码从Postgres转换为Oracle?
答案 0 :(得分:2)
Oracle 11.2支持递归CTE。但它不符合标准,因为recursive
关键字不是必需的(实际上:不得使用)。因此,如果您删除recursive
关键字并获得正确的CTE列定义,则以下内容应该有效。您还需要使用与LEVEL
不同的内容,因为这是一个保留字。
with cte (id1, id2, lvl) as (
select id1, id2, 1 as lvl
from t
union all
select t.id1, cte.id2, cte.lvl + 1
from t
join cte on t.id2 = cte.id1
)
select id1,
id2,
dense_rank() over (order by grp) as label
from (
select id1,
id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
lvl
from cte
) t
where lvl = 1;
这是一个SQLFiddle示例:http://sqlfiddle.com/#!4/deeb2/3
但是我怀疑原始查询是否正确,因为您没有递归CTE的“起始条件”。联合的第一部分检索表的所有行。应该有条件将其限制在层次结构的“根”,除非我误解了查询的目的。
递归CTE也可以用CONNECT BY
查询替换,在您的情况下,这将是:
select id1, id2, level as lvl
from t
connect by prior id1 = id2;
您可以将其与原始查询结合使用:
with cte (id1, id2, lvl) as (
select id1, id2, level as lvl
from t
connect by prior id1 = id2
)
select id1,
id2,
dense_rank() over (order by grp) as label
from (
select id1,
id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
lvl
from cte
) t
where lvl = 1;
虽然我认为它应该是相同的,但似乎层次结构以不同的顺序遍历。可能是因为递归CTE首先是广度,而connect by
是深度优先递归(或者反过来)。
第二个版本的SQLFiddle示例:http://sqlfiddle.com/#!4/deeb2/4