在Postgres中使用sum进行递归查询

Gui*_*sta 3 sql postgresql recursion common-table-expression

我必须在我的数据库中存储很多项目.每个项目都可以有子项目.结构看起来像一棵树:

                                     Project
                            /           |             \
                    ProjectChild1    ProjectChild2    [...]    ProjectChild[n]
                    /       |
 ProjectChildOfChild1    ProjectChildOfChild2
Run Code Online (Sandbox Code Playgroud)

树的层次是未知的.我正在考虑创建一个这样的表:

Projects:

project_ID id_unique PRIMARY_KEY
project_NAME text
project_VALUE numeric
project_PARENT id_unique
Run Code Online (Sandbox Code Playgroud)

在这种情况下,列project_PARENT将存储父项目的id(如果存在).

对于我的应用程序,我需要检索项目的总值,为此我需要总结每个项目子项和根项目的值.

我知道我需要使用递归,但我不知道如何在Postgres中这样做.

小智 6

像这样的东西:

with recursive project_tree as (
   select project_id, 
          project_name,
          project_value,
          project_parent
   from projects
   where project_id = 42 -- << the id of the "base" project
   union all 
   select p.project_id,
          p.project_name,
          p.project_value,
          p.project_parent
   from projects p
     join project_tree t on t.project_id = p.project_parent
)
select sum(project_value)
from project_tree;
Run Code Online (Sandbox Code Playgroud)

联合的第一部分需要选择您要评估的项目(“子”项目)。递归连接将沿着树向上走并检索所有父项目。


Erw*_*ter 6

这是@ a_horse 正确答案的简化版本(在评论中与OP讨论后).
适用于递归中任何(合理有限的)级别.

给定的总价格 project_id

WITH RECURSIVE cte AS (
   SELECT project_id AS project_parent, project_value
   FROM   projects
   WHERE  project_id = 1 -- enter id of the base project here !

   UNION  ALL 
   SELECT p.project_id, p.project_value
   FROM   cte
   JOIN   projects p USING (project_parent)
)
SELECT sum(project_value) AS total_value
FROM   cte;
Run Code Online (Sandbox Code Playgroud)

要一次性获得所有项目的总成本:

对于所有项目一次

WITH RECURSIVE cte AS (
   SELECT project_id, project_id AS project_parent, project_value
   FROM   projects
   WHERE  project_parent IS NULL  -- all base projects

   UNION  ALL 
   SELECT c.project_id, p.project_id, p.project_value
   FROM   cte c
   JOIN   projects p USING (project_parent)
)
SELECT project_id, sum(project_value) AS total_value
FROM   cte
GROUP  BY 1
ORDER  BY 1;
Run Code Online (Sandbox Code Playgroud)

SQL Fiddle(带有正确的测试用例).