Oracle SQL 分层查询自下而上

问题描述

我有一个表格,我想在其中使用分层查询从下到上。

问题是我需要使用 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;

Fiddle Demo.

,

一种可能性是首先从根开始执行分层查询 - 获取每一行的根节点

第二个步骤中,您执行自下而上的查询(从所有叶子节点开始)并使用预先计算的根节点

在解决方案下方使用 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 的顺序是您想要的自下而上的顺序,但在您的示例输出中未能达到。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...