Oracle SQL 自下而上的分层查询

Oracle SQL hierarchical query from bottom to top

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

问题是我需要使用 CONNECT_BY_ROOT 从根(顶部)获取一列的值,但是因为我颠倒了分层查询的工作方式(颠倒了 connect by 和 start与), 这个函数 (CONNECT_BY_ROOT) 将我的 'start with' 行视为级别 1 (root) 然后得到这个值。

换句话说,我想要一种方法来反转 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

编辑: 我忘了提到在我的真实系统中我正在处理数百万行数据,这就是我首先反转层次查询的原因就是为了在性能方面做得更好!

你快到了

 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.

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

second 步骤中执行自底向上查询(从所有 leaves 节点开始)并使用预先计算的 根节点

下面的解决方案使用Recursive Subquery Factoring

with hir (id, id_parent, value, value_root) as
(select id, id_parent, value, 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, id_parent, value, value_root) as 
(select id, id_parent, value, 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, value_root  
from hir2
;

        ID      VALUE VALUE_ROOT
---------- ---------- ----------
         3                     5
         2          9          5
         1          5          5

请注意,3, 2, 1 行的顺序是您想要的自下而上的顺序,但在您的示例输出中无法达到。

您可以向上检索所有树的根(在您的情况下是底部节点),然后应用按根划分的分析函数将父值转换为所有树节点。这对于 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, 2, 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
  , parentid
  , val
  , max(decode(connect_by_isleaf, 1, 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, 2, 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