问题描述
问题是我需要使用 CONNECT_BY_ROOT
从根(顶部)获取一列的值,但是因为我颠倒了分层查询的工作方式(颠倒了 connect by 和 start with 中的先验) ,此函数 (CONNECT_BY_ROOT
) 将我的“开始于”行视为级别 1(根),然后为我获取此值。
换句话说,我想要一种方法来反转 CONNECT_BY_ROOT
以从最后一个可能的级别而不是根获取列的值。
+----+-----------+-------+
| ID | ID_PARENT | VALUE |
+----+-----------+-------+
| 1 | null | 5 |
| 2 | 1 | 9 |
| 3 | 2 | null |
+----+-----------+-------+
我想像这样将 ID = 1 (5) 的值转换为 ID = 3:
+----+-------+------------+
| ID | VALUE | VALUE_root |
+----+-------+------------+
| 1 | 5 | 5 |
| 2 | 9 | 5 |
| 3 | null | 5 |
+----+-------+------------+
我试过了,但我得到的只是 null
作为 value_root:
SELECT id,CONNECT_BY_ROOT VALUE as VALUE_root
FROM my_table
START WITH ID = 3
CONNECT BY ID = PRIOR ID_PARENT
编辑:我忘了提到,在我的真实系统中,我正在处理数百万行数据,我首先反转分层查询的原因是为了让它更好在性能方面!
解决方法
您可以向上检索所有树的根(在您的情况下是底部节点),然后应用由根分区的分析函数将父值转换为所有树节点。这也适用于 start with
中的多个节点。
with src (id,parentid,val) as (
select 1,cast(null as int),5 from dual union all
select 2,1,9 from dual union all
select 3,2,null from dual union all
select 4,null from dual union all
select 5,null,10 from dual union all
select 6,5,7 from dual
)
select
connect_by_root id as tree_id,id,val,max(decode(connect_by_isleaf,val))
over(partition by connect_by_root id) as val_root
from src
start with id in (3,4,6)
connect by id = prior parentid
order by 1,3
TREE_ID | ID | PARENTID | VAL | VAL_ROOT |
---|---|---|---|---|
3 | 1 | - | 5 | 5 |
3 | 2 | 1 | 9 | 5 |
3 | 3 | 2 | - | 5 |
4 | 1 | - | 5 | 5 |
4 | 2 | 1 | 9 | 5 |
4 | 4 | 2 | - | 5 |
6 | 5 | - | 10 | 10 |
6 | 6 | 5 | 7 | 10 |
你快到了
SELECT id,value,CONNECT_BY_ROOT VALUE as VALUE_root
FROM your_table
START WITH ID = 1
CONNECT BY prior ID = ID_PARENT
,
您可以在这里尝试以下查询我刚刚更新了 START WITH 条件和 CONNECT BY 子句 -
SELECT id,CONNECT_BY_ROOT VALUE as VALUE_root
FROM my_table
START WITH ID = 1
CONNECT BY PRIOR ID = ID_PARENT;
,
一种可能性是首先从根开始执行分层查询 - 获取每一行的根节点。
在第二个步骤中,您执行自下而上的查询(从所有叶子节点开始)并使用预先计算的根节点
在解决方案下方使用 Recursive Subquery Factoring
with hir (id,id_parent,value_root) as
(select id,value value_root
from tab
where id_parent is null
union all
select tab.id,tab.id_parent,tab.value,hir.value_root
from hir
join tab on tab.id_parent = hir.id
),hir2 (id,value_root) as
(select id,value_root from hir
where ID in (select id from tab /* id of leaves */
minus
select id_parent from tab)
union all
select hir.id,hir.id_parent,hir.value,hir.value_root
from hir2
join hir on hir2.id_parent = hir.id
)
select id,value_root
from hir2
;
ID VALUE VALUE_ROOT
---------- ---------- ----------
3 5
2 9 5
1 5 5
注意行 3,1
的顺序是您想要的自下而上的顺序,但在您的示例输出中未能达到。