【问题标题】:Oracle SQL hierarchical query from bottom to topOracle SQL从下到上分层查询
【发布时间】:2021-07-23 13:33:51
【问题描述】:

我有一个表,我想使用分层查询从底部到顶部。

问题是我需要使用CONNECT_BY_ROOT 从根(顶部)获取一列的值,但是由于我颠倒了分层查询的工作方式(颠倒连接前的先验和开头),这函数 (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

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

【问题讨论】:

    标签: sql oracle hierarchical-query


    【解决方案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

    【讨论】:

    • 我收到此错误:unable to extend temp segment by %s in tablespace %s 我正在处理大量数据,不仅是 3 行,还有其他方法吗?
    • 嗯,另一种方法是递归 CTE,但我认为它需要或多或少相同数量的内存。你start with单个id时会不会出现这个错误?
    • 当我输入一个 ID 时,它工作得很好.. 但它比这更复杂.. 我必须从 date = today 列开始,这样我才能选择今天的所有数据并计算它们的 val_root .. (它带有 null 作为值)当我这样做时它不起作用它让我今天所有 ID 的 val_root 作为一个唯一的 val_root 这是错误的值。
    • 那么您的connect by 定义不正确。您需要提供适当的样本数据和所需的输出。也许分层查询不是应该使用的
    • @akadri01 对于所有具有相同祖父母的叶子。这就是您在问题中描述的要求。或者有什么不同的规则?层次结构呢:没有递归查询就无法遍历层次结构
    【解决方案2】:

    您可以在此处尝试以下查询 我刚刚更新了 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.

    【讨论】:

    • 不完全是我想要的。我忘了提到,在我的真实系统中,我正在处理数百万个数据,所以为了获得更好的性能,我真的需要从 ID=3 开始并上升。此外,我通常不知道哪个 ID 是我的 ID=3 的根,所以我必须从 ID_PARENT 为 null 开始,这将花费大量时间和资源。我希望这能解释为什么我必须从 ID=3 开始
    【解决方案3】:

    你快到了

     SELECT id,
            value,
            CONNECT_BY_ROOT VALUE as VALUE_root
       FROM your_table
      START WITH ID = 1
    CONNECT BY prior ID = ID_PARENT
    

    【讨论】:

    • 不完全是我想要的。我忘了提到,在我的真实系统中,我正在处理数百万个数据,所以为了获得更好的性能,我真的需要从 ID=3 开始并上升。此外,我通常不知道哪个 ID 是我的 ID=3 的根,所以我必须从 ID_PARENT 为 null 开始,这将花费大量时间和资源。我希望这能解释为什么我必须从 ID=3 开始。
    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多