SET search_path='tmp'; DROP TABLE targets CASCADE; CREATE TABLE targets ( id integer not null primary key , parent_id integer references targets(id) , expected_target integer ); INSERT INTO targets(id,parent_id,expected_target) VALUES (1,NULL, 1000), (2,1, 500), (3,2, 200); WITH RECURSIVE zzz AS ( SELECT t0.id, t0.parent_id , 0::integer AS level , t0.expected_target FROM targets t0 WHERE t0.parent_id IS NULL UNION SELECT t1.id, t1.parent_id , 1+zzz.level AS level , t1.expected_target FROM targets t1 JOIN zzz ON zzz.id = t1.parent_id ) SELECT * FROM zzz ;
OUTPUT:
SET DROP TABLE NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "targets_pkey" for table "targets" CREATE TABLE INSERT 0 3 id | parent_id | level | expected_target
UPDATE: if you do not want the whole tree, the true tree and nothing but the tree, but only part of its subtree, you can, of course, change the conditions a bit:
WITH RECURSIVE zzz AS ( SELECT t0.id, t0.parent_id , 0::integer AS level , t0.expected_target FROM targets t0
source share