Recursive common table expressions (CTE) for arbitrary depth hierarchies
- Posted by Michael MacDonald
- on Aug, 30, 2017
- in SQL
- Blog No Comments.
The challenge of storing an arbitrary depth hierarchy isn’t so much with the storing of it as it is with the querying it and rendering it in a useful fashion.
Given a simple hierarchy stored in a table that has a self-referential parent_id such as:
create table hierarchy ( id integer NOT NULL, parent_id integer, name varchar, CONSTRAINT pk1 PRIMARY KEY (id), CONSTRAINT fk_self FOREIGN KEY (parent_id) REFERENCES hierarchy (id) );
With some sample data:
insert into hierarchy (id,parent_id,name) values (1,null,'A') ,(2,1,'B') ,(3,1,'C') ,(4,1,'D') ,(5,2,'E') ,(6,2,'F') ,(7,6,'G') ,(8,6,'H') ,(9,7,'I') ,(10,7,'J') ,(11,4,'K') ,(12,4,'L') ,(13,11,'M') ;
We can extract the data:
with recursive hierarchy_cte (id,parent_id,name, lvl,lineage) as
(
/* base query */
select
id
, parent_id
, name
, 0 lvl
, name lineage
from
hierarchy
where
parent_id is null
union all
/* recursing query */
select
h.id
, h.parent_id
, h.name
, lvl+1
, concat(lineage, ' ', h.name) lineage
from
hierarchy h
inner join hierarchy_cte c on
h.parent_id=c.id
)
/* reporting query */
select
concat(repeat('-',lvl * 4),Name) Tree
,hc.*
from
hierarchy_cte hc
order by
lineage
, name
Which yields the following results:
| tree | id | parent_id | name | lvl | lineage |
|---|---|---|---|---|---|
| A | 1 | (null) | A | 0 | A |
| —-B | 2 | 1 | B | 1 | A B |
| ——–E | 5 | 2 | E | 2 | A B E |
| ——–F | 6 | 2 | F | 2 | A B F |
| ————G | 7 | 6 | G | 3 | A B F G |
| —————-I | 9 | 7 | I | 4 | A B F G I |
| —————-J | 10 | 7 | J | 4 | A B F G J |
| ————H | 8 | 6 | H | 3 | A B F H |
| —-C | 3 | 1 | C | 1 | A C |
| —-D | 4 | 1 | D | 1 | A D |
| ——–K | 11 | 4 | K | 2 | A D K |
| ————M | 13 | 11 | M | 3 | A D K M |
| ——–L | 12 | 4 | L | 2 | A D L |
Related
Comments & Responses
Recent Posts
- The shape of structured data
- Writing very small executable
- The challenge of type asserting []interface{} to string slices.
- Serializing/Deserializing a complex GO struct to store externally (i.e. in a database, redis, or text file)
- Fun with golang, Google Maps api, and proxying requests
