-1

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

4

1 回答 1

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

于 2013-08-23T20:49:46.250 回答