Postgresql query for getting n-level parent-child relation stored in a single table
With Postgres you can use a recursive common table expression:
with recursive rel_tree as (
select rel_id, rel_name, rel_parent, 1 as level, array[rel_id] as path_info
from relations
where rel_parent is null
union all
select c.rel_id, rpad(' ', p.level * 2) || c.rel_name, c.rel_parent, p.level + 1, p.path_info||c.rel_id
from relations c
join rel_tree p on c.rel_parent = p.rel_id
)
select rel_id, rel_name
from rel_tree
order by path_info;
SQLFiddle based on your example: http://sqlfiddle.com/#!11/59319/19
(I replaced the spaces for indention with underscores as SQLFiddle doesn't display the spaces correctly)
Related videos on Youtube
saji89
My work is usually in Laravel Framework, earlier I had worked on Zend framework, Joomla development, and Facebook application development based on Facebook Javascript API and PHP API. Now I'm learning Python(loving it totally ;) ). I love to experiment with opensource software and above all, to learn new things and update myself with the latest of technologies. In my free time I love reading books.
Updated on February 03, 2020Comments
-
saji89 over 4 years
I have a table denoting parent-child relations. The relations can go n-level deep.
I have created a sample table using the following query:
CREATE SEQUENCE relations_rel_id_seq INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; CREATE TABLE relations( rel_id bigint DEFAULT nextval('relations_rel_id_seq'::regclass) NOT NULL PRIMARY KEY, rel_name text, rel_display text, rel_parent bigint );
I need to query the table and display the parent-child relations hierarchically. I'm still not getting an idea regarding how to query n-level deep using sql query.
For the sqlfiddle eg, the expected hierarchy of output:
rel1 rel11 rel111 rel112 rel1121 rel2 rel21 rel211 rel212
N.B: The value n, in
n-level
is unknown.DB Design:
Is there any better way such a relation can be expressed in the database for easy querying.?
-
mu is too short over 11 yearsYou're probably looking for WITH RECURSIVE, there's an example over here.
-
saji89 over 11 years@muistooshort, Thanks for the suggestion. 'll look into it. Do you have any suggestion for alternative db design, that can make it easier for querying and retrieving relations in such cases?
-
Ihor Romanchenko over 11 years@saji89 Read
this
page of the manual. It describesWITH RECURSIVE
queries you need. -
Ihor Romanchenko over 11 years@saji89 BTW It is good to mention your RDBMS version. Recursive queries aren't available in PostgreSQL below 8.4.
-
mu is too short over 11 yearsI find the
rel_parent
structure that you have to be the most natural design for trees; it makes sense and, given WITH RECURSIVE, is easy to work with for all the usual operations. You could look at "nested sets" and "materialized paths" I suppose.
-
-
tscho over 11 yearsGreat answer, exactly what the OP is looking for! But there is a little mistake in the
rpad(..)
part, changed it torpad('', p.level * 2, ' ')
. Again space is replaced with '_' on SQL Fiddle. -
tscho over 11 yearsJust checked the docs: space is the default fill character (optional 3rd parameter), so I had to use the '_' fill character explicitly on SQLFiddle.
-
saji89 over 11 years+1, Wow.
Postgresql
doesn't cease to surprise me. Thankyou. -
mkataja almost 9 yearsFor a moment I was at a loss as to how to use a normal
with
expression together withwith recursive
. Seems like you're supposed to put thewith
expression inside thewith recursive
. -
a_horse_with_no_name almost 9 years@mkataja: no, you just add it.
with recursive first_cte (...), second_cte (...) select * from second_cte
. Therecursive
keyword is only required once together with the initialwith
keyword - regardless which CTE is recursive. -
mkataja almost 9 yearsHeh, that makes sense. Somehow I thought the
recursive
keyword needs to be together with the actual recursive CTE(s).