特殊累积和基于前一行的行数据转换

Yan*_*eve 5 postgresql migration window-functions

根据对这个问题回答,我设法产生了以下输出以获得运行的值总和:

id      creation                    operation       value       running sum
SyJw-c  2016-09-01 00:11:08.307419  positive_op_1   1.33        28.82
SyJw-c  2016-08-21 08:32:54.431662  negative_op_1   -1          27.49
SyJw-c  2016-08-18 07:38:33.878365  positive_op_2   1           28.49
SyJw-c  2016-08-14 18:12:03.599797  negative_op_1   -1          27.49
SyJw-c  2016-08-02 15:44:29.693303  positive_op_1   1.33        28.49
SyJw-c  2016-07-31 12:08:50.659905  override_op_1   4.66        27.16
SyJw-c  2016-06-26 06:53:54.537603  negative_op_1   -3.5        22.5
SyJw-c  2016-05-31 13:34:08.005687  negative_op_1   -1          26
SyJw-c  2016-05-31 13:34:04.776970  negative_op_1   -1          27
SyJw-c  2016-05-31 11:27:09.502983  override_op_2   28          28
Run Code Online (Sandbox Code Playgroud)

我的情况更复杂。我不仅需要对这些值求和,还需要能够首先根据其下方行的运行总和对某些行执行转换。

我先解释一下动机:

目前我有一个带有增量、减量和覆盖操作的表。我想将数据移植到一个只有增量和减量操作的表中,这样我就可以直接总结这些值。我不希望维护旧表,只是一种将数据迁移到更简单模型的方法,因此只将数据附加到新表。

采用上面的“原始”表,我想编写一个查询(我在 postgresql 9.5 上运行)并获得一个与下面非常相似的表。(相反,我想知道我正在尝试的是不可能的

请注意,覆盖运算符散布在普通运算符之间,它们可能像示例中那样出现两次以上,此外,所有初始运算符(表中最早的)都被覆盖,并带有应在示例中考虑的初始值以下。此外,我只显示了属于一个组(相同 ID)的数据,但总体思路是为所有组执行此迁移。最后我在括号中显示数学,我不需要在结果中,它仅用于示例:

id      creation    oper      transformed_op   value   transformed_value       running sum
SyJw-c  2016- ...  pos_op_1                    1.33    1.33                    10.98
SyJw-c  2016- ...  neg_op_1                    -1      -1                      9.65
SyJw-c  2016- ...  pos_op_2                    1       1                       10.65
SyJw-c  2016- ...  neg_op_1                    -1      -1                      9.65
SyJw-c  2016- ...  pos_op_1                    1.33    1.33                    10.65
SyJw-c  2016- ...  ovr_op_1   new_rel_op_1     4.66    (4.66-22.5) = -17.84    4.66
SyJw-c  2016- ...  neg_op_1                    -3.5    -3.5                    22.5
SyJw-c  2016- ...  neg_op_1                    -1      -1                      26
SyJw-c  2016- ...  neg_op_1                    -1      -1                      27
SyJw-c  2016- ...  ovr_op_2   new_rel_op_2     28      (28-0) = 28             28
Run Code Online (Sandbox Code Playgroud)

该表按从后到前的顺序显示。该22.526 - 3.5。这个减法应该做 ( this_value - previous_sum) 取决于 的值transformed_op。当原始op是一个时,override op我想根据处理它的行的运行总和(按创建排序desc)执行一些操作,在这种情况下,从value列中的值中减去该运行总和值。

Erw*_*ter 5

基于此表定义:

CREATE TABLE tbl (  -- no PK?
  id text NOT NULL
, creation timestamp UNIQUE NOT NULL
, operation text NOT NULL
, value numeric NOT NULL
, running_sum numeric  -- optional (not needed for task)
);
Run Code Online (Sandbox Code Playgroud)

数据类型和约束几乎总是必不可少的。
creation严格来说不一定是唯一的。但如果每个组 ( id)可以有重复的值,您需要做更多。)

计算特殊运行总和的基本查询

SELECT id, creation, operation, value
     , sum(value) OVER (PARTITION BY id, run ORDER BY creation) AS running_sum
FROM   (
   SELECT *, count(*) FILTER (WHERE operation  LIKE 'override_op_%')
                      OVER (PARTITION BY id ORDER BY creation) AS run
   FROM   tbl
   ) t
ORDER  BY id, creation DESC;
Run Code Online (Sandbox Code Playgroud)

任何以“override_op_”开头的操作名称都表示新运行(组、补丁、分区)的开始。

除了您已经链接到的相关答案之外:

考虑这个相关问题以了解如何将行分成组的详细信息(run在此查询中,因为您对id列使用术语“组” )

我使用新的聚合FILTER子句进行部分计数:

您可以在旧版本中使用更简单(不太清楚)的表达式:

count(operation LIKE 'override_op_%' OR NULL)
Run Code Online (Sandbox Code Playgroud)

计算增量

基于此,您可以轻松计算所需的增量:

SELECT *
     , running_sum - lag(running_sum, 1, numeric '0')  -- data type must match!
                     OVER (PARTITION BY id ORDER BY creation) AS transformed_value 
FROM (
   SELECT id, creation, operation, value
        , sum(value) OVER (PARTITION BY id, run ORDER BY creation) AS running_sum
   FROM   (
      SELECT *, count(*) FILTER (WHERE operation  LIKE 'override_op_%')
                OVER (PARTITION BY id ORDER BY creation) AS run
      FROM   tbl
      ) t
   ) t
ORDER  BY id, creation DESC;
Run Code Online (Sandbox Code Playgroud)

我使用窗口函数lag()的 3 参数形式提供0(数据类型必须匹配!)作为表中第一行的默认值。