【问题标题】:Cumulative sum over a table一张表的累计金额
【发布时间】:2014-07-20 15:22:23
【问题描述】:

在 Postgres 中对表执行累积求和的最佳方法是什么,以便在向表中添加更多字段/列的情况下带来最佳性能和灵活性。

表格

a b d 1 59 15 181 2 16 268 3 219 4 102

累积

a b d 1 59 15 181 2 31 449 3 668 4 770

【问题讨论】:

  • SQL 表表示无序集。您需要一列来指定排序。我假设第一列数字代表数据中的这个值。
  • 我认为您的示例应该包括这样一种情况,即一行的值 之前的行具有 NULL 值。在这种情况下,结果应该是什么样的?
  • 是的,欧文,谢谢!您和其他答案很有帮助!我正在寻找一种方法来获得每组值的总和!毕竟没那么难:)

标签: sql postgresql window-functions cumulative-sum


【解决方案1】:

您可以使用窗口函数,但您需要额外的逻辑来避免存在NULLs 的值:

SELECT id,
       (case when a is not null then sum(a) OVER (ORDER BY id) end) as a,
       (case when b is not null then sum(b) OVER (ORDER BY id) end) as b,
       (case when d is not null then sum(d) OVER (ORDER BY id) end) as d 
FROM table;

这假定指定排序的第一列称为id

【讨论】:

  • NULL 不是对求和没有影响吗?
  • 完美的戈登!谢谢
  • 是的 sqlfiddle.com/#!12/ac0af/3/0 ,@vol7ron 我相信他这样做是为了避免重复向下运行总数。 IE。否则 A 列中的 59 将重复 3 次。想要的结果只显示一次。
  • 正确@BrianDeMilia!也感谢你的例子。
  • 嗯,有道理,这意味着您的数据也需要预先排序,对吧?如果d 在中间行的某处有一个NULL,我猜记录会中断,那么总和将在下一个记录中继续 - 这听起来对吗?
【解决方案2】:

运行求和的窗口函数。

SELECT sum(a) OVER (ORDER BY d) as "a",
       sum(b) OVER (ORDER BY d) as "b",
       sum(d) OVER (ORDER BY d) as "d" 
FROM table;

如果您有多个运行总和,请确保订单相同。


请务必注意,如果您希望您的列在您的问题中显示为汇总表(每个字段唯一排序),则需要更多的参与。


更新:我已修改查询以进行所需的排序,但没有给定的公共字段。

SQL 小提琴:(1) Only Aggregates,或(2) Source Data Beside Running Sum

WITH 
rcd AS ( 
  select row_number() OVER() as num,a,b,d 
  from tbl
),
sorted_a AS (
  select row_number() OVER(w1) as num, sum(a) over(w2) a
  from tbl
  window w1 as (order by a nulls last),
         w2 as (order by a nulls first)
),
sorted_b AS (
  select row_number() OVER(w1) as num, sum(b) over(w2) b
  from tbl
  window w1 as (order by b nulls last),
         w2 as (order by b nulls first)
),
sorted_d AS (
  select row_number() OVER(w1) as num, sum(d) over(w2) d
  from tbl
  window w1 as (order by d nulls last),
         w2 as (order by d nulls first)
)

SELECT sorted_a.a, sorted_b.b, sorted_d.d 
FROM rcd 
JOIN sorted_a USING(num)
JOIN sorted_b USING(num)
JOIN sorted_d USING(num)
ORDER BY num;

【讨论】:

  • 嗨,vol7ron,是的,这行得通,尽管有一个问题。首先我忘了给第一个(索引)列命名,假设它叫做'I'。我相信在您的示例中,窗口函数将使用...(ORDER BY I)。尽管如此,这不会以上述格式输出 cumulative 表,其中有“空”单元格。您的解决方案将输出类似
    60;15;181 60;31;451 60;31;670 60;31;784 
  • @Algina 我已经更新了答案。它不像 Gordon 或我的原版那样紧凑,但它会处理排序,并且不需要 id 字段。如果源数据已经预先排序,请使用 Gordon's;否则,您需要对各个字段进行排序,然后将它们连接在一起,就像上面的编辑一样。
  • 酷,这也有效,看到另一种方法很酷。非常好!谢谢
  • 这有利于处理中行休息。我已经更新以显示在总列旁边显示源数据是多么容易。
【解决方案3】:

我认为你真正想要的是:

SELECT id
     , sum(a) OVER (PARTITION BY a_grp ORDER BY id) as a
     , sum(b) OVER (PARTITION BY b_grp ORDER BY id) as b
     , sum(d) OVER (PARTITION BY d_grp ORDER BY id) as d 
FROM  (
   SELECT *
        , count(a IS NULL OR NULL) OVER (ORDER BY id) as a_grp
        , count(b IS NULL OR NULL) OVER (ORDER BY id) as b_grp
        , count(d IS NULL OR NULL) OVER (ORDER BY id) as d_grp
   FROM   tbl
   ) sub
ORDER  BY id;

表达式count(col IS NULL OR NULL) OVER (ORDER BY id) 在子查询sub 中形成abd 的连续非空行组。

在外部查询中,我们运行每组的累积总和。 NULL 值形成自己的组并自动保留NULL。无需额外的CASE 声明。

SQL Fiddle(为列a添加了一些值来演示效果)。

【讨论】:

  • 我可能遗漏了一些东西——在小提琴中,A 列没有排序并且没有累积和
  • @vol7ron:小提琴帽有两个查询,第一个是你的比较,第二个是我的。我现在简化为只显示我的查询。
  • 是的,但是当我查看您的表格时,“A”列没有报告正确的值(现在仍然不是)
  • @vol7ron:A 的值在两个小提琴 AFAIUI 中都是正确的。我认为这就是 OP 真正要寻找的:对每组值求和。
  • 完全同意。我刚刚重新阅读了戈登回答中的评论。我认为他是在描述带走 d3 (219) 并将其替换为 NULL 值。代替 NULL,它将是另一个 449(如 d2),将 NULL 计为 0 并继续这样做,直到遇到下一个整数;然而,他没有开始新的总和,而是恢复累计总数(他的意思是551,而不是说102)。我可能弄错了,但认为 Gordon 提出一个新问题或修改当前问题是正确的。
猜你喜欢
  • 2017-08-01
  • 1970-01-01
  • 2016-03-27
  • 2017-09-28
  • 2022-10-25
  • 2023-03-15
  • 1970-01-01
  • 2020-09-12
  • 2021-03-16
相关资源
最近更新 更多