with recursive descendants(parent, child) as (select p.p, p.c from kids p where not exists (select 1 from kids c where c.c = p.p) group by p.p, p.c union all select k.* from kids k, descendants d where k.p = d.child) select * from descendants; parent | child --------+------- 1 | 3 1 | 2 1 | 4 2 | 21 2 | 22 2 | 23 22 | 221 22 | 222 (8 rows) with recursive descendants(parent, child) as (select p.p, p.c from kids p where not exists (select 1 from kids c where c.c = p.p) group by p.p, p.c union all select k.* from kids k, descendants d where k.p = d.child) select d.parent, array_agg(d.child) from descendants d group by d.parent; parent | array_agg --------+------------ 1 | {3,2,4} 22 | {221,222} 2 | {21,22,23} (3 rows) |