如何将代码从Postgres转换为Oracle

时间:2013-08-23 20:27:44

标签: oracle postgresql

我有一个源表(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?

1 个答案:

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