获取Oracle上的层次结构级别和所有节点引用
我一直在读有关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
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比分层查询快得多。它工作起来很有魅力!关于术语,我完全同意,我的英语真的很差,我把所有的东西都命名错了。它很有魅力!关于术语,我完全同意,我的英语是