Reputation: 455
Following is the table format that I have. Table name :: USERS
userid reporttouserid
------ ------------
101 NULL
102 101
103 102
Now I need a query to list all the child user ids under 101 that is 102 and 103 both (103 is indirectly under 101 as its parent 102 is under 101)
I have seen the common table expression in postgresql but not being able to figure out how to go about it.
Upvotes: 1
Views: 1655
Reputation: 325141
The PostgreSQL documentation covers this topic. See the examples given for recursive CTEs on that page.
Recursive CTEs can be a bit hard to grasp, but are very powerful once you use them. Read the documentation and experiment a little; you'll get it.
(Please always mention your PostgreSQL version and show desired output in table-like form in your questions).
Given demo data:
create table users (
userid integer primary key,
reporttouserid integer references users(userid)
);
insert into users(userid, reporttouserid) values (101,null), (102,101), (103,102);
(please provide this in questions where possible, it's a pain to have to create it)
you can recursively walk the graph with something like:
WITH RECURSIVE flatusers(userid, reporttouserid, baseuserid) AS (
SELECT userid, reporttouserid, userid AS baseuserid
FROM users WHERE reporttouserid IS NULL
UNION ALL
SELECT u.userid, u.reporttouserid, f.baseuserid
FROM flatusers f
INNER JOIN users u ON f.userid = u.reporttouserid
)
SELECT * FROM flatusers;
producing output like:
userid | reporttouserid | baseuserid
--------+----------------+------------
101 | | 101
102 | 101 | 101
103 | 102 | 101
(3 rows)
I'm sure you can figure out where to go from there. Make sure you understand that recursive CTE before using it.
Be aware that PostgreSQL (9.4 or older at least) cannot (unfortunately) push quals down into CTE terms, even for non-recursive CTEs. If you add WHERE baseuserid = 101
to your query, the query will still generate the entire flattened table, then throw most of it away. If you want to do this recursive operation for just one baseuserid, you must add the appropriate WHERE
clause term after WHERE reporttouserid IS NULL
in the static union part of the recursive CTE term.
Upvotes: 6