递归计数sql

时间:2015-07-21 03:52:55

标签: sql postgresql recursion count

我有这样的表:

id    activity            pay       parent   
1     pay all             -         null     
2     pay tax             10 $      1        
3     pay water bills     -         1        
4     fix house           -         null     
5     fix roof            1 $       4          
6     pay drinking water  1 $       3        

我想得到这样的表:

id    activity            pay       parent   matriks
1     pay all             {11 $}    null     1       (pay tax + pay water bills)
2     pay tax             10 $      1        1-2
3     pay water bills     {1 $}     1        1-3     (pay drinking water)
4     fix house           {1 $}     null     4       (fix roof)
5     fix roof            1 $       4        4-5     
6     pay drinking water  1 $       3        1-3-6

从孩子到父母的数量: 问题是当水费不计入饮用水时,如果缴纳税款或支付水没有支付价值,则无法支付所有费用。

1 个答案:

答案 0 :(得分:2)

我在我们的postgres db(版本8.4.22)上试过这个,因为小提琴对我来说有点慢。但SQL可以粘贴在那里,它适用于postgres。

仍然是fiddle demo第一次拿20秒,但后来更快。

这是为我生成计算结果的原因。 (我没有根据你的要求对其进行格式化,因为在我看来,主要的练习是计算。)这假设你的表被称为activity

with recursive rekmatriks as(
    select id, activity, pay, parent, id::text as matriks, 0 as lev
        from activity
        where parent is null
    union all
    select activity.id, activity.activity, activity.pay, activity.parent,
           rekmatriks.matriks || '-' || activity.id::text as matriks,
           rekmatriks.lev+1 as lev
        from activity inner join rekmatriks on activity.parent = rekmatriks.id
)
, reksum as (
    select id, activity, pay, parent, matriks, lev, coalesce(pay,0) as subsum
        from rekmatriks
        where not exists(select id from rekmatriks rmi where rmi.parent=rekmatriks.id)
    union all
    select rekmatriks.*, reksum.subsum+coalesce(rekmatriks.pay, 0) as subsum
        from rekmatriks inner join reksum on rekmatriks.id = reksum.parent)

select id, activity, pay, parent, matriks, sum(subsum) as amount, lev
    from reksum
group by id, activity, pay, parent, matriks, lev
order by id

作为奖励,它提供了id的嵌套深度。 0表示父级,1表示第一个子级等。这使用两个递归WITH queries来实现您想要的。您需要的计算值位于amount列。

第一个(rekmatriks)从上到下处理表格中的ID,从父级为NULL的任何ID开始。递归部分只需获取父ID并将其自己的id添加到其中,以实现您的matriks树表示字段。

第二个(reksum)从下到上工作,并从没有子元素的所有行开始。此查询的递归部分为非递归部分中选择的每个子行选择父行,并计算每行的paysubsum之和。这会为每个id生成多行,因为一个父级可以有多个子级。

现在剩下的就是最后的选择陈述。它使用GROUP BYSUM将多个可能的子总和值聚合到一行中。

这适用于您的特定示例。如果样本数据中未显示不同的情况,则可能会失败,例如,如果包含子项的项目带有需要添加的值。