【问题标题】:Recursive count sql递归计数sql
【发布时间】:2015-10-10 09:01:59
【问题描述】:

我有这样的表:

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

从孩子到父母的计数: 问题是当水费不计入饮用水时,如果交税或支付的水没有支付价值,都不能计算。

【问题讨论】:

  • 当你说 table 时,你是指 db 还是 php?如果 db 你使用的是什么 RDBMS?那些{} 是什么?
  • 什么是矩阵?你的逻辑是什么?
  • @jWeaver 如果是付费饮用水1-3-6 我认为是因为添加到行1, 3 and 6 -- pay all, pay water, pay drinking
  • 就像 6 的父级是 3,3 的父级是 1 所以 1-3-6 ,为了清楚起见,他应该使用 1->3->6
  • @JuanCarlosOropeza 我使用来自孩子的 postgre,{} 值,这在右表中解释,exp:支付水费,它有孩子支付饮用水,价值 1 美元,它算作父母(支付水费)

标签: sql postgresql recursion count


【解决方案1】:

我在我们的 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 添加到其中,以实现您的矩阵树表示字段。

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

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

这确实适用于您的特定示例。如果示例数据中没有显示不同的情况,例如,如果具有子项的项目带有需要添加的值,则它可能会失败。

【讨论】:

  • 非常好。唯一的问题是格式,不知道 OP 是否对 put pay 很严格 {10 $} 和 matriks 1 (pay tax + pay water bills)
  • 哦...太好了,这解决了我的问题!谢谢大家,谢谢@takrl
猜你喜欢
  • 2019-09-03
  • 2011-07-19
  • 2014-12-28
  • 2015-01-08
  • 2019-11-24
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 2010-10-07
相关资源
最近更新 更多