如何在sql oracle中使用自动跳转功能获取父子关系

8gsdolmq  于 2023-01-25  发布在  Oracle
关注(0)|答案(2)|浏览(99)

我在SQL Oracle中有一个表,其中包含一些步骤。
| 步|自动跳过|
| - ------|- ------|
| 无||
| 十个||
| 二十个|跳越|
| 二十一|跳越|
| 三十||
我想得到一个有子公司和母公司的表。母公司是下一步。这是很容易做到的线索:

select step as child,LEAD (step,1) OVER (ORDER BY step) AS parent from STEPS

但这是棘手的部分。当auto_skip列中有"skip"值时,必须生成第二个子/父。然后我们必须在没有skip值的情况下进行下一步。因此,对于此示例,我的子/父的结果必须为:
| 儿童|母体|
| - ------|- ------|
| 无|十个|
| 十个|二十个|
| 二十个|二十一|
| 二十一|三十|
| 三十||
| 十个|三十|
添加以下内容以更清楚:跳步有时会不一样,当增加了相同的跳步后,下一步会一直跳到该步有不同的跳步或没有跳步为止。
例如:
| 步|自动跳过|
| - ------|- ------|
| 无||
| 十个||
| 二十个|跳过1|
| 二十一|跳过1|
| 二十二|跳过2|
| 三十||
应该成为
| 儿童|母体|
| - ------|- ------|
| 无|十个|
| 十个|二十个|
| 十个|二十二|
| 二十一|二十二|
| 二十一|三十|
| 二十二|三十|
| 二十个|二十一|
| 三十||

toiithl6

toiithl61#

这个怎么样(根据你的样本数据和结果)。如果你的数据很大,也许有更好的解决方案。而且你没有指定如果30也是20的父:

with steps as (
    select 0 step, cast(null as varchar2(10)) auto_skip from dual
    union ALL
    select 10,null from dual
    union all
    select 20, 'skip' from dual
    union all
    select 21,'skip' from dual
    union all 
    select 30 ,null from dual
)
select step as child,LEAD (step,1) OVER (ORDER BY step) AS parent from STEPS
union
select step as child,LEAD (step,1) OVER (ORDER BY step) AS parent from STEPS where auto_skip is null;

CHILD PARENT 
----- ------ 
    0     10 
   10     20 
   20     21 
   21     30 
   30        
   10     30 
9nvpjoqh

9nvpjoqh2#

试试这个解决方案,用UNION两种不同的方法来计算父节点,第二种方法是递归的,必须区分几次跳跃或只有一次跳跃。它可以在测试数据上工作,但应该在更多的数据上检查。

with data(step,auto_skip) as (
    select 0, null from dual union all
    select 10, null  from dual union all
    select 20, 'skip1' from dual union all
    select 21, 'skip1' from dual union all
    select 22, 'skip2' from dual union all
    select 30, null  from dual -- union all
),
pdata as (
    select d.* from (
        select d.step, d.auto_skip, 
            lead(d.step,1) over(order by d.step) as natural_father,
            lead(d.auto_skip,1) over(order by d.step) as natural_father_skip
        from data d
    ) d
),
rdata as (
    select level as lvl, connect_by_isleaf as isleaf, connect_by_root(step) as rstep, d.* 
    from pdata d
    start with natural_father_skip <> nvl(auto_skip,'*')
    connect by 
        prior natural_father = step and prior natural_father_skip = auto_skip
)
select * from (
    select step as child, natural_father as parent from pdata
    union all
    select rstep, case when lvl > 2 then step else natural_father end from rdata
    where isleaf = 1 
)
order by child, parent
;

0   10
10  20
10  22
20  21
21  22
21  30
22  30
30

相关问题