sqlgraphtreehierarchyascii-art

SQL Challenge/Puzzle: How to create an ASCII art hierarchy tree with an SQL query?


This was posted on my 1st day on StackOverflow.
It was not really a question, but a knowledge sharing.

Today this question got the "Popular Question Badge".

Popular Question Badge


The initial motivation for this one, was to display Oracles' actual execution plans, saved in GV$SQL_PLAN, in a visual, clear way.



#Requirements#

Input

Output

Code

##Sample data##

create table h (id int,pid int);

insert into h (id,pid) values (0  ,null);
insert into h (id,pid) values (1  ,0   );
insert into h (id,pid) values (2  ,1   );
insert into h (id,pid) values (3  ,2   );
insert into h (id,pid) values (4  ,3   );
insert into h (id,pid) values (5  ,4   );
insert into h (id,pid) values (6  ,3   );
insert into h (id,pid) values (7  ,6   );
insert into h (id,pid) values (8  ,7   );
insert into h (id,pid) values (9  ,8   );
insert into h (id,pid) values (10 ,9   );
insert into h (id,pid) values (11 ,10  );
insert into h (id,pid) values (12 ,9   );
insert into h (id,pid) values (13 ,12  );
insert into h (id,pid) values (14 ,8   );
insert into h (id,pid) values (15 ,6   );
insert into h (id,pid) values (16 ,15  );
insert into h (id,pid) values (17 ,6   );
insert into h (id,pid) values (18 ,17  );
insert into h (id,pid) values (19 ,17  );
insert into h (id,pid) values (20 ,3   );
insert into h (id,pid) values (21 ,20  );
insert into h (id,pid) values (22 ,21  );
insert into h (id,pid) values (23 ,22  );
insert into h (id,pid) values (24 ,21  );

##Results##

###Vertical siblings###

|
|____ 1
     |
     |____ 2
          |
          |____ 3
               |
               |____ 4
               |    |
               |    |____ 5
               |
               |____ 6
               |    |
               |    |____ 7
               |    |    |
               |    |    |____ 8
               |    |         |
               |    |         |____ 9
               |    |         |    |
               |    |         |    |____ 10
               |    |         |    |    |
               |    |         |    |    |____ 11
               |    |         |    |
               |    |         |    |____ 12
               |    |         |         |
               |    |         |         |____ 13
               |    |         |
               |    |         |____ 14
               |    |
               |    |____ 15
               |    |    |
               |    |    |____ 16
               |    |
               |    |____ 17
               |         |
               |         |____ 18
               |         |
               |         |____ 19
               |
               |____ 20
                    |
                    |____ 21
                         |
                         |____ 22
                         |    |
                         |    |____ 23
                         |
                         |____ 24

###Horizontal siblings###

                      |                      
                      |                      
                      |                      
                      0                      
                      |                      
                      |                      
                      |                      
                      |                      
                      |                      
                      1                      
                      |                      
                      |                      
                      |                      
                      |                      
                      |                      
                      2                      
                      |                      
                      |                      
                      |                      
                      |                      
                      |                      
                      3                      
                      |                      
                      |                      
  ---------------------------------------    
  |                 |                   |    
  |                 |                   |    
  4                 6                   20   
  |                 |                   |    
  |                 |                   |    
  |         -------------------         |    
  |         |         |       |         |    
  |         |         |       |         |    
  5         7         15      17        21   
            |         |       |         |    
            |         |       |         |    
            |         |    ------    ------  
            |         |    |    |    |    |  
            |         |    |    |    |    |  
            8         16   18   19   22   24 
            |                        |       
            |                        |       
          --------                   |  
          |      |                   |  
          |      |                   |  
          9      14                  23 
          |                             
          |                             
       ------  
       |    |  
       |    |  
       10   12 
       |    |  
       |    |  
       |    |  
       |    |  
       |    |  
       11   13 
           
           

Solution

  • SQLite

    Vertical siblings

    with        last_sibling (id)
                as
                (
                    select      max (id)
                    from        h
                    group by    pid
                )
    
               ,tree (id,branch,path)
                as
                (
                    select      1       as id
                               ,''      as branch
                               ,'001'   as path
    
                    union all
    
                    select      h.id
                               ,t.branch || case when ls.id is not null then ' ' else '|' end || '    '
                               ,t.path || '_' || substr ('00000' || h.id,-5)
    
                    from                    tree            t
    
                                left join   last_sibling    ls
    
                                on          ls.id   =
                                            t.id
    
                                join        h
    
                                on          h.pid =
                                            t.id
                )
    
               ,vertical_space (n)
                as
                (
                    select      1
    
                    union all
    
                    select      vs.n + 1
                    from        vertical_space  vs
                    where       vs.n < 2
                )
    
    select      t.branch || case vs.n when 1 then '|____' || ' ' || cast (t.id as text) else '|' end
    
    from                    tree            t
    
                cross join  vertical_space  vs
    
    order by    t.path
               ,vs.n desc
    ;