Search code examples
sqloraclegrouping-sets

How to make SQL query with grouping in each node of an hierarchy tree?


There is a table with an usual "child-to-parent" structure, where each node has weight.

TREE_TABLE
----------------------------------------
   id  | parent_id  |  name    | weight
----------------------------------------
   1   |  NULL      |   N1     |   51
   2   |  1         |   N12    |   62
   3   |  1         |   N13    |   73
   4   |  2         |   N124   |   84
   5   |  2         |   N125   |   95

// for convenience the "name" column shows path from a node to the root node

How to build a SQL query that results in a set of rows where each row represents grouping per particular node and its children?

Please, use any SQL dialect on your choice. Just need a general idea or a prototype of the solution.

To solve this problem, I am experimenting with GROUPING SETS and ROLLUP report, but can't figure out the way of handling "dynamic" number of grouping levels.

Example of expected query result:

RESULT
--------------------------
 name  |  summary_weight
--------------------------
  N1   |   (51+62+73+84+95)
  N12  |   (62+84+95)    
  N124 |   (84)
  N125 |   (95)
  N13  |   (73)

Solution

  • for example:

    with 
     datum(id,parent_id,name,weight)
     as
     (
     select 1,NULL,'N1',51 from dual union all
     select 2 ,  1 , 'N12' , 62  from dual union all
     select 3 ,  1 , 'N13' , 73 from dual union all
     select 4 ,  2 , 'N124' , 84 from dual union all
     select 5 ,  2 , 'N125' , 95 from dual
     ),
     step1 as
     (
     select id,parent_id,name,weight, connect_by_root name  root,connect_by_isleaf is_parent 
     from datum
     connect by prior id = parent_id 
     )
    select root,sum(weight)  sum_w,
     '('||listagg(weight,'+') within group(order by null) ||')' str_w,
     '('||listagg(name,'+') within group(order by null) ||')' str_n
    from step1
    group by root
    order by 1;
    

    enter image description here

    link: Hierarchical Queries