postgres hierarchy - count of child levels and sort by date of children or grandchildren postgres hierarchy - count of child levels and sort by date of children or grandchildren postgresql postgresql

postgres hierarchy - count of child levels and sort by date of children or grandchildren


create table mytable ( id serial primary key, parent_id int references mytable, postdate date );create index mytable_parent_id_idx on mytable (parent_id);insert into mytable (id, parent_id, postdate) values (1, null, '2015-03-10');insert into mytable (id, parent_id, postdate) values (2, 1, '2015-03-11');insert into mytable (id, parent_id, postdate) values (3, 1, '2015-03-12');insert into mytable (id, parent_id, postdate) values (4, 3, '2015-03-13');insert into mytable (id, parent_id, postdate) values (5, null, '2015-03-14');insert into mytable (id, parent_id, postdate) values (6, null, '2015-03-15');insert into mytable (id, parent_id, postdate) values (7, 6, '2015-03-16');with recursive recu as (  select id as parent, id as root, null::date as child_postdate    from mytable   where parent_id is null   union all  select r.parent, mytable.id, mytable.postdate    from recu r    join mytable      on parent_id = r.root)select m.id, c.cnt, m.postdate, c.max_child_date  from mytable m  join ( select parent, count(*) as cnt, max(child_postdate) as max_child_date           from recu          group by parent       ) c on c.parent = m.id order by c.max_child_date desc nulls last, m.postdate desc;


You'll need a recursive query to count the elements in the subtrees:

WITH RECURSIVE opa AS (        SELECT id AS par        , id AS moi        FROM the_tree        WHERE parent_id IS NULL        UNION ALL        SELECT o.par AS par        , t.id AS moi        FROM opa o        JOIN the_tree t ON t.parent_id = o.moi        )SELECT t.id        , c.cnt        , t.postdateFROM the_tree tJOIN ( SELECT par, COUNT(*) AS cnt        FROM opa o        GROUP BY par        ) c ON c.par = t.idORDER BY t.id        ;

UPDATE (it appears the OP also wants the maxdate per tree)

        -- The same, but also select the postdate        -- --------------------------------------WITH RECURSIVE opa AS (        SELECT id AS par        , id AS moi        , postdate AS postdate        FROM the_tree        WHERE parent_id IS NULL        UNION ALL        SELECT o.par AS par        , t.id AS moi        -- , GREATEST(o.postdate,t.postdate) AS postdate        , t.postdate AS postdate        FROM opa o        JOIN the_tree t ON t.parent_id = o.moi        )SELECT t.id        , c.cnt        , t.postdate        , c.maxdateFROM the_tree tJOIN ( SELECT par, COUNT(*) AS cnt        , MAX(o.postdate) AS maxdate -- and obtain the max()        FROM opa o        GROUP BY par        ) c ON c.par = t.idORDER BY c.maxdate, t.id        ;


After looking at everyone's code, I created the subquery I needed. I can use PHP to vary the 'case when' code depending on the user's sort selection. For instance, the code below will sort the root nodes based on child level 1's postdate.

with recursive cte as (select id as parent, id as root, null::timestamp as child_postdate,0 as depthfrom mytablewhere parent_id = -1union allselect r.parent, mytable.id, mytable.postdate,depth+1from cte rjoin mytable  on parent_id = r.root)select m.id, c.cnt, m.postdatefrom ssf.dtb_021 mjoin ( select parent, count(*) as cnt, max(child_postdate) as max_child_date,depth       from cte       group by parent,depth     ) c on c.parent = m.idorder by   case    when depth=2 then 1    when depth=1 then 2    else 0  end DESC,c.max_child_date desc nulls last, m.postdate desc;