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.5
是26 - 3.5
。这个减法应该做 ( this_value - previous_sum
) 取决于 的值transformed_op
。当原始op
是一个时,override op
我想根据处理它的行的运行总和(按创建排序desc
)执行一些操作,在这种情况下,从value
列中的值中减去该运行总和值。
基于此表定义:
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
(数据类型必须匹配!)作为表中第一行的默认值。