Search code examples
sqloracle-databaseoracle11gconnect-bytransitive-closure-table

Finding the "deepest" child in a hierarchical query


I need some help querying hierarchical data. Here is the single, simple, table, where parent_id references id and may be null for root entries.

  create table edition (
      id           NUMBER(20),
      parent_id    NUMBER(20)
  );

For each record in the table I need to find the deepest child having maximum id. If a record has no children, then its own id should be returned. I tried by myself but failed using START WITH A.id = B.id where A and B are subqueries, looks like Oracle doesn't allow such joins.

Here is the sample data:

     id      parent_id
   ----------------------
      1        NULL
      2           1
      3           1
      4           1
      5           4
      6           5
      7           5

and a sample result

     id      result
   ----------------------
      1           7
      2           2
      3           3
      4           7
      5           7
      6           6
      7           7

Solution

  • I believe you want to try

    create table tq84_edition (
      id        number primary key,
      parent_id number references tq84_edition
    );
    
    insert into tq84_edition values (  1, null);
    insert into tq84_edition values (  2,    1);
    insert into tq84_edition values (  3,    1);
    insert into tq84_edition values (  4,    1);
    insert into tq84_edition values (  5,    4);
    insert into tq84_edition values (  6,    5);
    insert into tq84_edition values (  7,    5);
    
    
    with x (root, id, parent_id, lvl) as (
                   select id    root,
                          id,
                          parent_id,
                          1 lvl
                    from  tq84_edition
            UNION ALL
                   select x.root  root,
                          tq84_edition.id,
                          tq84_edition.parent_id,
                          x.lvl + 1 lvl
                     from x,
                          tq84_edition
                    where x.id = tq84_edition.parent_id
    )
    select  root, max(id) keep (dense_rank last order by lvl, id)
      from x
     group by root;