oraclesql中的循环

oraclesql中的循环,sql,oracle,loops,plsql,Sql,Oracle,Loops,Plsql,我想将列ID_最后添加到下面左侧的表中。示例表由6行和8行的两个序列组成。我需要处理许多序列和每个序列未知/无限行数/每个序列循环数。当ID不在ID_new中时,序列开始,当ID_new不在ID中时,序列停止。我想知道序列中所有ID的最后一个ID_new(如右表所示) 如何使用SQL(oracle)实现这一点 非常感谢您的帮助 您没有给出表名,因此我假设它的名称为table1 下面是一个查询,用于查找层次结构中每个节点的叶节点。请注意,如果您的任何节点有多个子节点,您将获得一些重复的节点 --

我想将列ID_最后添加到下面左侧的表中。示例表由6行和8行的两个序列组成。我需要处理许多序列和每个序列未知/无限行数/每个序列循环数。当ID不在ID_new中时,序列开始,当ID_new不在ID中时,序列停止。我想知道序列中所有ID的最后一个ID_new(如右表所示)

如何使用SQL(oracle)实现这一点

非常感谢您的帮助


您没有给出表名,因此我假设它的名称为table1

下面是一个查询,用于查找层次结构中每个节点的叶节点。请注意,如果您的任何节点有多个子节点,您将获得一些重复的节点

-- sample data
with table1 as (select 11 as id, 12 as id_new from dual
    union all select 12, 5 from dual
    union all select 5, 18 from dual
    union all select 18, 17 from dual
    union all select 17, 28 from dual
    union all select 28, 13 from dual
    union all select 25, 31 from dual
    union all select 31, 22 from dual
    union all select 22, 41 from dual
    union all select 41, 33 from dual
    union all select 33, 39 from dual
    union all select 39, 30 from dual
    union all select 30, 45 from dual
    union all select 45, 24 from dual)
-- query
select regexp_substr(id_path, '[^>]+', 1, 1) as root, 
  id_new as id_last
from (select CONNECT_BY_ISLEAF isleaf, sys_connect_by_path(id, '>') as id_path, id_new
      from table1
      connect by prior id_new = id)
where isleaf = 1
;
我认为这应该作为一个更新语句,但我还没有测试它

merge into table1 t
  using (select regexp_substr(id_path, '[^>]+', 1, 1) root, id_new as id_last
        from (select CONNECT_BY_ISLEAF isleaf, sys_connect_by_path(r.id, '>') as id_path, r.id_new
              from table1 r
              connect by prior r.id_new = r.id)
        where isleaf = 1) u
  on (t.id = u.root)
when matched then update
  set t.id_last = u.id_last;

如果您使用的是Oracle 11gR2或更高版本,则可以使用如下递归查询(假设您的表名为
tbl
):


这不涉及循环(我没有得到对我的评论的回复)。

因为任何序列中的最后一个ID都可以通过此查询确定:

select id_new from YourData yd
 where not exists (select 1 from YourData yd2
                    where yd2.id = yd.id_new);
我们可以将该问题视为以标识的ID\u Last值为根的分层查询,将根ID作为ID\u Last返回:

select id
     , id_new
     , CONNECT_BY_ROOT id_new ID_Last
  from YourData yd
  connect by NOCYCLE id_new = prior id
 start with not exists (select 1 from YourData yd2
                         where yd2.id = yd.id_new)
或者,可以将其编写为递归查询,使用上面的第一个查询(带有附加列)作为锚查询。为了避免循环,我们必须添加一列来跟踪已经访问过的节点,并在查询的递归部分进行检查:

With Recur(id, id_new, id_last, nodes) as (
  select id
       , id_new
       , id_new
       , ':'||id||':'
    from YourData yd1
   where not exists (select 1 from YourData yd2
                      where yd2.id = yd1.id_new)
   union all
  select yd.id
       , yd.id_new
       , r.id_last
       , r.nodes||yd.id||':'
    from YourData yd
    join Recur r
      on r.id = yd.id_new
     and r.nodes not like '%:'||yd.id||':%' -- Avoid cycles
)
select id, id_new, id_last
  from Recur
 order by id_last
     , nodes desc;

您是否打算仅使用SELECT and JOIN或带有游标和循环的PL/SQL块来实现此功能?能否给出一个循环示例,以及这些循环的期望输出是什么?我计划在informatica powercenter中实现它(可能在源代码限定符中)。不过,这个工具并不重要。只需要新的列ID,还有其他列指示ID的实际顺序吗?你怎么知道它应该从Id=11开始?然后以id=45结束?这是可行的,但不是最优的,因为它需要做大量的工作才能找到答案。它在同一棵树上移动多次,因为每个记录都被视为一个树根来查找它的叶节点。这会生成大量额外的数据,然后需要由输出查询唯一运算符清除这些数据。通过在ID上使用
CONNECT\u by\u root
而不是
SYS\u CONNECT\u by\u PATH
(除非您使用的是Oracle 9i或更早版本),您可以更简单地确定根目录。然而,像@trincot一样,您要多次遍历同一棵树以获得答案,而每棵树只遍历一次就足够了。
With Recur(id, id_new, id_last, nodes) as (
  select id
       , id_new
       , id_new
       , ':'||id||':'
    from YourData yd1
   where not exists (select 1 from YourData yd2
                      where yd2.id = yd1.id_new)
   union all
  select yd.id
       , yd.id_new
       , r.id_last
       , r.nodes||yd.id||':'
    from YourData yd
    join Recur r
      on r.id = yd.id_new
     and r.nodes not like '%:'||yd.id||':%' -- Avoid cycles
)
select id, id_new, id_last
  from Recur
 order by id_last
     , nodes desc;