获取Oracle上的层次结构级别和所有节点引用

获取Oracle上的层次结构级别和所有节点引用,oracle,Oracle,我一直在读有关Oracle中的connectby和CTE的文章,但我找不到解决方案。我不知道如何正确使用connectby来满足我的需要,Oracle中的递归CTE仅限于2个分支(一个UNION ALL),我使用3个分支 在SQL Server中,我发现这一点后,感觉很简单。我只添加了另一个关于返回所有节点引用的UNION ALL 我想做的是建立这样的层次结构: Code|Father 1 |NULL 2 |1 3 |2 这应该会回报我: Node|Father|Level|Jum

我一直在读有关Oracle中的
connectby
和CTE的文章,但我找不到解决方案。我不知道如何正确使用
connectby
来满足我的需要,Oracle中的递归CTE仅限于2个分支(一个
UNION ALL
),我使用3个分支

在SQL Server中,我发现这一点后,感觉很简单。我只添加了另一个关于返回所有节点引用的
UNION ALL

我想做的是建立这样的层次结构:

Code|Father
1   |NULL
2   |1
3   |2
这应该会回报我:

Node|Father|Level|JumpsToFather
1   |1     |1    |0
2   |1     |2    |1
2   |2     |2    |0
3   |1     |3    |2
3   |2     |3    |1
3   |3     |3    |0

注意:是的,我需要返回一个对自身的引用,该引用在层次结构上计数为零跳跃

这里有一个使用递归CTE的解决方案。我使用了
lvl
作为列标题,因为
level
在Oracle中是一个保留字。您还将看到术语上的其他差异。我使用“父级”表示更高级别,使用“祖先级”表示>=0步(以满足您将节点显示为自己祖先的要求)。我使用了一个
orderby
子句使输出与您的匹配;您可能需要也可能不需要对行进行排序

你的问题促使我再次更详细地阅读分层查询,看看是否可以用它们而不是递归CTE来实现。事实上我已经知道你可以,通过使用
CONNECT\u by\u PATH
,但是使用
substr
,仅仅检索分层路径中的顶层并不能令人满意,必须有更好的方法。(如果这是使用分层查询的唯一方法,我肯定会选择递归CTE路线,如果它可用的话)。如果我能找到一个好的,我将在这里添加分层查询解决方案

with h (      node, parent ) as (
       select 1   , null  from dual union all
       select 2   , 1     from dual union all
       select 3   , 2     from dual
     ),
     r (      node  , ancestor, steps ) as (
       select node  , node    , 0    
       from   h
       union all
       select r.node, h.parent, steps + 1
       from   h join r
                on h.node = r.ancestor
     ) 
select   node, ancestor, 
         1+ (max(steps) over (partition by node)) as lvl, steps
from     r
where    ancestor is not null
order by lvl, steps desc;


      NODE   ANCESTOR        LVL      STEPS
---------- ---------- ---------- ----------
         1          1          1          0
         2          1          2          1
         2          2          2          0
         3          1          3          2
         3          2          3          1
         3          3          3          0
添加了:分层查询解决方案

好的,找到了。请测试这两种解决方案,看看哪种性能更好;从不同设置上的测试来看,递归CTE比分层查询快很多,但这可能取决于具体情况。另外:递归CTE仅在Oracle11.2及更高版本中有效;分层解决方案适用于旧版本

我添加了更多的测试数据来匹配安纳托利的

with h (      node, parent ) as (
       select 1   , null  from dual union all
       select 2   , 1     from dual union all
       select 3   , 2     from dual union all
       select 4   , 2     from dual union all
       select 5   , 4     from dual
     )
select                                             node, 
           connect_by_root node                 as ancestor, 
           max(level) over (partition by node)  as lvl,
           level - 1                            as steps
from       h
connect by parent = prior node
order by   node, ancestor;



      NODE   ANCESTOR        LVL      STEPS
---------- ---------- ---------- ----------
         1          1          1          0
         2          1          2          1
         2          2          2          0
         3          1          3          2
         3          2          3          1
         3          3          3          0
         4          1          3          2
         4          2          3          1
         4          4          3          0
         5          1          4          3
         5          2          4          2
         5          4          4          1
         5          5          4          0

下面是一个使用递归CTE的解决方案。我使用了
lvl
作为列标题,因为
level
在Oracle中是一个保留字。您还将看到术语上的其他差异。我使用“父级”表示更高级别,使用“祖先级”表示>=0步(以满足您将节点显示为自己祖先的要求)。我使用了一个
orderby
子句使输出与您的匹配;您可能需要也可能不需要对行进行排序

你的问题促使我再次更详细地阅读分层查询,看看是否可以用它们而不是递归CTE来实现。事实上我已经知道你可以,通过使用
CONNECT\u by\u PATH
,但是使用
substr
,仅仅检索分层路径中的顶层并不能令人满意,必须有更好的方法。(如果这是使用分层查询的唯一方法,我肯定会选择递归CTE路线,如果它可用的话)。如果我能找到一个好的,我将在这里添加分层查询解决方案

with h (      node, parent ) as (
       select 1   , null  from dual union all
       select 2   , 1     from dual union all
       select 3   , 2     from dual
     ),
     r (      node  , ancestor, steps ) as (
       select node  , node    , 0    
       from   h
       union all
       select r.node, h.parent, steps + 1
       from   h join r
                on h.node = r.ancestor
     ) 
select   node, ancestor, 
         1+ (max(steps) over (partition by node)) as lvl, steps
from     r
where    ancestor is not null
order by lvl, steps desc;


      NODE   ANCESTOR        LVL      STEPS
---------- ---------- ---------- ----------
         1          1          1          0
         2          1          2          1
         2          2          2          0
         3          1          3          2
         3          2          3          1
         3          3          3          0
添加了:分层查询解决方案

好的,找到了。请测试这两种解决方案,看看哪种性能更好;从不同设置上的测试来看,递归CTE比分层查询快很多,但这可能取决于具体情况。另外:递归CTE仅在Oracle11.2及更高版本中有效;分层解决方案适用于旧版本

我添加了更多的测试数据来匹配安纳托利的

with h (      node, parent ) as (
       select 1   , null  from dual union all
       select 2   , 1     from dual union all
       select 3   , 2     from dual union all
       select 4   , 2     from dual union all
       select 5   , 4     from dual
     )
select                                             node, 
           connect_by_root node                 as ancestor, 
           max(level) over (partition by node)  as lvl,
           level - 1                            as steps
from       h
connect by parent = prior node
order by   node, ancestor;



      NODE   ANCESTOR        LVL      STEPS
---------- ---------- ---------- ----------
         1          1          1          0
         2          1          2          1
         2          2          2          0
         3          1          3          2
         3          2          3          1
         3          3          3          0
         4          1          3          2
         4          2          3          1
         4          4          3          0
         5          1          4          3
         5          2          4          2
         5          4          4          1
         5          5          4          0

对于这个问题,我花了1个小时写了这个:

with t as ( select code, parent, level l
              from (select 1 as code, NULL as parent from dual union
                    select 2 , 1 from dual union 
                    select 3 , 2 from dual 
                    -- add some more data for demo case
                    union 
                    select 4 , 2 from dual union 
                    select 5 , 4 from dual 
                    )
              start with parent is null
            connect by prior code = parent )

select code, (select code 
                from t t1 
               where l = ll 
                 and rownum = 1
                start with t1.code = main_t.code
               connect by prior t1.parent = t1.code 
                 ) parent, 
       l code_level, 
       jumps
from (
select distinct t.*, l-level jumps, level ll
  from t
 connect by level <= l
 ) main_t
order by code, parent

对于这个问题,我花了1个小时写了这个:

with t as ( select code, parent, level l
              from (select 1 as code, NULL as parent from dual union
                    select 2 , 1 from dual union 
                    select 3 , 2 from dual 
                    -- add some more data for demo case
                    union 
                    select 4 , 2 from dual union 
                    select 5 , 4 from dual 
                    )
              start with parent is null
            connect by prior code = parent )

select code, (select code 
                from t t1 
               where l = ll 
                 and rownum = 1
                start with t1.code = main_t.code
               connect by prior t1.parent = t1.code 
                 ) parent, 
       l code_level, 
       jumps
from (
select distinct t.*, l-level jumps, level ll
  from t
 connect by level <= l
 ) main_t
order by code, parent

Oracle中的CTE不限于
union
union all
中的两个分支。递归CTE是以这种方式限制的,但可能这不是您的意思,因为递归CTE自版本11第2版起仅在Oracle中可用,而您在Oracle 10上。然而,对于一般的解决方案,您需要递归CTE,所以不清楚您真正想要什么。仅适用于最多3个级别的解决方案?它还将有助于显示问题中输入的格式。@mathguy True。TBH,如果我需要说我只有一个针对Oracle 11 R2的解决方案,我可以。我编辑了这个问题,以最好地说明数据是如何存储在表中的,并更正了提到递归CTEs的术语。好的,使用分层查询找到了正确的解决方案。我将把它添加到我的答案中。您可能想测试这两种解决方案,看看哪种更快;从一些实验(使用不同的设置)来看,递归CTE比分层查询快得多。Oracle中的CTE不限于
union
union all
中的两个分支。递归CTE是以这种方式限制的,但可能这不是您的意思,因为递归CTE自版本11第2版起仅在Oracle中可用,而您在Oracle 10上。然而,对于一般的解决方案,您需要递归CTE,所以不清楚您真正想要什么。仅适用于最多3个级别的解决方案?它还将有助于显示问题中输入的格式。@mathguy True。TBH,如果我需要说我只有一个针对Oracle 11 R2的解决方案,我可以。我编辑了这个问题,以最好地说明数据是如何存储在表中的,并更正了提到递归CTEs的术语。好的,使用分层查询找到了正确的解决方案。我将把它添加到我的答案中。您可能想测试这两种解决方案,看看哪种更快;从一些实验(使用不同的设置)来看,递归CTE比分层查询快得多。它工作起来很有魅力!关于术语,我完全同意,我的英语真的很差,我把所有的东西都命名错了。它很有魅力!关于术语,我完全同意,我的英语是