postgres层次结构 - 子级别的计数,按子项或孙子的日期排序

时间:2015-05-01 14:22:05

标签: postgresql sorting hierarchy children

我想知道如何编写postgres子查询,以便下表示例将输出我需要的内容。

id   parent_id    postdate

1      -1      2015-03-10 
2     1      2015-03-11  (child level 1)
3     1      2015-03-12  (child level 1)
4     3      2015-03-13  (child level 2)
5    -1      2015-03-14
6    -1      2015-03-15
7     6      2015-03-16  (child level 1)

如果我想按子级别1对所有根id进行排序,并计算父级的子级数,则输出将是这样的

id    count      date
6   2     2015-03-15
1   4     2015-03-10
5   1     2015-03-14

输出根据root的子节点按postdate排序。输出的“日期”是根的过期日期。即使id#5有更新的postdate,rootid#6的孩子(id#7)也有最新的postdate,因为它是按孩子的postdate排序的。 id#5没有任何孩子所以它只是放在最后,按日期排序。 'count'是孩子(孩子1级),孙子(孩子2级)和自己(root)的数字。例如,id#2,#3,#4都属于id#1,因此对于id#1,计数将为4。

到目前为止我当前的子查询:

SELECT p1.id,count(p1.id),p1.postdate
 FROM mytable p1
     LEFT JOIN mytable c1 ON c1.parent_id = p1.id AND p1.parent_id = -1
     LEFT JOIN mytable c2 ON c2.parent_id = c1.id AND p1.parent_id = -1
GROUP BY p1.id,c1.postdate,p1.postdate
ORDER by c1.postdate DESC,p1.postdate DESC

3 个答案:

答案 0 :(得分:1)

您需要递归查询来计算子树中的元素:

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.postdate
FROM the_tree t
JOIN ( SELECT par, COUNT(*) AS cnt
        FROM opa o
        GROUP BY par
        ) c ON c.par = t.id
ORDER BY t.id
        ;

UPDATE(看起来OP也想要每棵树的maxdate)

        -- 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.maxdate
FROM the_tree t
JOIN ( 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.id
ORDER BY c.maxdate, t.id
        ;

答案 1 :(得分:0)

select
 p.id,
 (1+c.n) as parent_post_plus_number_of_subposts,
 p.postdate
from 
    table as p
inner join

    (
    select
    parent_id, count(*) as n, max(postdate) as _postdate
    from table
    group by parent_id
    ) as c

on p.id = c.parent_id
where p.parent_id = -1
order by c._postdate desc

答案 2 :(得分:0)

在查看每个人的代码之后,我创建了我需要的子查询。根据用户的排序选择,我可以使用PHP来改变'case when'代码。例如,下面的代码将根据子级别1的postdate对根节点进行排序。

with recursive cte as (
select id as parent, id as root, null::timestamp as child_postdate,0 as depth
from mytable
where parent_id = -1
union all
select r.parent, mytable.id, mytable.postdate,depth+1
from cte r
join mytable
  on parent_id = r.root
)
select m.id, c.cnt, m.postdate
from ssf.dtb_021 m
join ( select parent, count(*) as cnt, max(child_postdate) as max_child_date,depth
       from cte 
      group by parent,depth
     ) c on c.parent = m.id
order 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;