Problem
Playing around in DB2 I wanted to know how to create a hiearchical query. This because I wanted to create view for explain plans, a bit resembling the explain plans which oracle provides.
First step is understanding how to make the recursive SQL’s
The setup:
drop table relations; create table relations (id int, parent int); insert into relations values(0,NULL); insert into relations values(1,0); insert into relations values(2,1); insert into relations values(3,1); insert into relations values(4,3); insert into relations values(5,0); insert into relations values(6,5); insert into relations values(7,5); insert into relations values(8,6); insert into relations values(9,7); insert into relations values(10,0); insert into relations values(11,1); commit;
Just to be sure,it looks like:
ID PARENT ----------- ----------- 0 - 1 0 2 1 3 1 4 3 5 0 6 5 7 5 8 6 9 7 10 0 11 1
What I would like to see is something resembling following:
ID Parent 0 - 1 0 2 1 3 1 4 3 11 1 5 0 6 5 8 6 7 5 9 7 10 0
First try: (Recursive) Common Table Expressions (r)CTE
DB2 has a nice way to have recursion in r(CTE) let’s see if I can get that working:
with recur(id, parent, level) as ( select rel.id id, rel.parent parent, 1 level from relations rel where rel.id=0 union all select rel.id, rel.parent, rec.level+1 from recur rec, relations rel where rec.id=rel.parent and rec.level<10 ) select id, cast(lpad(parent, level*2, ' ') as varchar(20)) parent, level from recur;
This gives me the following result:
ID PARENT LEVEL ----------- -------------------- ----------- 0 - 1 1 0 2 5 0 2 10 0 2 2 1 3 3 1 3 11 1 3 6 5 3 7 5 3 4 3 4 8 6 4 9 7 4
This is somewhat resembling what I want. However, the query shows the rows all per level. After some searchinf I came to know that this is calles "Search Breadth First", what I need is "Search Dept First".
Tried a lot of things but to no avail.
On the net I came across the "Search Dept First" clause. This should then look like:
with recur(id, parent, level) as ( select rel.id id, rel.parent parent, 1 level from relations rel where rel.id=0 union all select rel.id, rel.parent, rec.level+1 from recur rec, relations rel where rec.id=rel.parent and rec.level<10 ) search depth first by parent set ordering select id, cast(lpad(parent, level*2, ' ') as varchar(20)) parent, level from recur order by ordering;
But ...NO....No luck there.
Second try: Hiearchical SQL
Another approach is using tha naticve hiearchical capabilities from the SQL implemantation:
select id, lpad(parent, level*2, ' ') parent, level from relations start with id=0 connect by prior id=parent;
This didn't work at first. We first need to tell DB2 that it can use also these type of features:
db2set DB2_COMPATIBILITY_VECTOR=08 db2stop db2start
Since I'm on my development environment, I can stop and start the database whenever it suits me 🙂
Following output was generated by running this query:
ID PARENT LEVEL ----------- ---------------- ----------- 0 - 1 1 0 2 2 1 3 3 1 3 4 3 4 11 1 3 5 0 2 6 5 3 8 6 4 7 5 3 9 7 4 10 0 2
Exactly what I want. So at least we have a solution.
(r)CTE revisited
I could not let go of the idea of CTE's so I posted on stackoverflow.com: Question.
"The Impaler" came up with the following:
with n (id, parent, lvl, ordering) as ( select id, parent, 1, lpad(id, 3, '0') || lpad('', 30, ' ') from relations where parent is null union all select r.id, r.parent, n.lvl + 1, trim(n.ordering) || '/' || lpad(r.id, 3, '0') from n, relations r where r.parent = n.id ) select id, lpad(parent, lvl * 2, ' ') as parent, lvl, ordering from n order by ordering;
Which delivers:
ID PARENT LVL ORDERING ----------- -------------------- ----------- ---------------------- 0 - 1 000 1 0 2 000/001 2 1 3 000/001/002 3 1 3 000/001/003 4 3 4 000/001/003/004 11 1 3 000/001/011 5 0 2 000/005 6 5 3 000/005/006 8 6 4 000/005/006/008 7 5 3 000/005/007 9 7 4 000/005/007/009 10 0 2 000/010
Hehe that works like a charm!!!
Thank you