Re: recursive WITH nested union ALL with NOCYCLE logic

From: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
To: Michael Moore <michaeljmoore(at)gmail(dot)com>
Cc: postgres list <pgsql-sql(at)postgresql(dot)org>
Subject: Re: recursive WITH nested union ALL with NOCYCLE logic
Date: 2016-03-18 21:32:42
Message-ID: CAKFQuwbd-eTDbHZCxtxg2ro8v3brDAhujcuYTdCUkqqVqNExsQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-sql

On Fri, Mar 18, 2016 at 2:06 PM, Michael Moore <michaeljmoore(at)gmail(dot)com>
wrote:

> I have two tables, 1 is a hierarchical table and the other a map to
> alternative hierarchies. Given a starting node, I need to be able to return
> the hierarchy and all related hierarchies.
>
> with
> recursive inn_t(keyv, val, parent) as (
> select * from (
> select key as keyv, val, parent
> from mike_hier hi where hi.key ='aaa'
> union all
> -- get all alt hierarchies
> select child ,null ,null from mike_map ma where ma.parent
> ='aaa' ) gg
> union all
> (
> with xxx as ( select * from inn_t i ) -- only a single reference
> allowed to inn_t
> select * from
> (
> select mh.key , mh.val , mh.parent
> from mike_hier mh
> where mh.parent in (select keyv from xxx) -- normally would
> join inn_t
> union all
> select child ,null ,null
> from mike_map ma
> where ma.parent in (select keyv from xxx) -- normally would
> join inn_t
> ) unionall
> )
> )
> select distinct * from inn_t where val is not null;
>
>
Where should I send the bill for the pain relievers :)

​with recursive --applies to the second CTE really but placed at the top by
convention (maybe by rule)
inn_t(keyv, val, parent) as ( --not recursive, no reference to inn_t in
this CTE
-- Given a base tree lets return all rows where it is the primary...
select * from (
select key as keyv, val, parent
from mike_hier hi where hi.key ='aaa'
-- ...as well as the primary rows for any of its alises (derived though
they may be it should work)
union all
-- get all alt hierarchies
select child ,null ,null from mike_map ma where ma.parent
='aaa' ) gg
), recurse_here_instead AS (
-- Now for each of the those primary rows locate in mike_heir locate the
direct descendants
-- and add them to the working set. On the next pass the original parents
will be skipped
-- because they were already processed but all of these newly added
children will be
-- put through the wringer to find their children.
select * from inn_t i --initial condition is a complex query so
simplify the recursive portion by referecing a CTE
UNION ALL
select mh.key , mh.val , mh.parent
from mike_hier mh
join inn_t ON (mh.parent = inn_t.keyv)
)
-- got rid of distinct...honestly not positive why but I suspect if you
write the query correct DISTINCT on the outer layer should
-- be redundant.
select * from recurse_here_instead where val is not null;

​I haven't yet coded a variation of this query that used the path array and
cycle-avoidance logic so I'm leaving that open for the moment. Now that
this is written more correctly incorporating that from other's examples
should be easier.

David J.
​

​
​

In response to

Responses

Browse pgsql-sql by date

  From Date Subject
Next Message Andrew Smith 2016-03-18 22:09:43 Re: Enhancement to SQL query capabilities
Previous Message Michael Moore 2016-03-18 21:06:16 recursive WITH nested union ALL with NOCYCLE logic