如何仅在连续行上应用聚合函数?
How to apply aggregate function only on contiguous rows?
在 PostgreSQL 9.4 上,我试图在一些连续的行上实现我将调用 "aggregate function" 的东西。示例:
输入数据:
recipe prod1 prod2 timestamp
0 5 4 2015-07-02 08:10:34.357
0 2 7 2015-07-02 08:13:45.352
0 7 0 2015-07-02 08:16:22.098
1 3 2 2015-07-02 08:22:14.678
1 9 4 2015-07-02 08:22:56.123
2 2 6 2015-07-02 08:26:37.564
2 1 7 2015-07-02 08:27:33.109
2 0 8 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210
期望的输出:
recipe prod1_sum prod2_avg timestamp_first timestamp_last
0 14 3.6666 2015-07-02 08:10:34.357 2015-07-02 08:16:22.098
1 12 3 2015-07-02 08:22:14.678 2015-07-02 08:22:56.123
2 3 7 2015-07-02 08:26:37.564 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210 2015-07-02 08:42:23.210
基本上,每个 "group" 连续行(当 table 在时间戳列上排序时)有一个输出行具有相同的 "recipe" 值。在输出中,prod1_sum是"group"中prod1的总和,prod2_avg是相同"group"中prod2的平均值,最后2列分别是第一列和组中的最后一个时间戳。显然有几个不同的组具有相同的 "recipe" 值,我确实希望每个组都有一个输出行。
目前,我有一种基于几个请求和数据库外部的大量数据处理来获取它的丑陋方法,我真的很想避免这种情况,但不值得展示。
我的问题确实是 "grouping" 行。我知道如何创建一个聚合函数来做我想做的事,如果我可以将它单独应用于每个组的话。我研究了 windows 函数,但似乎这会按配方对所有值进行分组,不符合我需要遵守的 "contiguous rows" 原则。
您可以使用以下查询:
SELECT recipe, SUM(prod1) AS prod1_sum,
AVG(prod2) AS prod2_avg,
MIN(timestamp) AS timestamp_first, MAX(timestamp) AS timestamp_last
FROM (
SELECT recipe, prod1, prod2, timestamp,
ROW_NUMBER() OVER (ORDER BY timestamp)
-
ROW_NUMBER() OVER (PARTITION BY recipe
ORDER BY timestamp) AS grp
FROM mytable ) t
GROUP BY recipe, grp
ORDER BY timestamp_first
这里的技巧是使用 ROW_NUMBER
window 函数来识别连续 recipe
值的孤岛:grp
计算字段正是这样做的。
在 PostgreSQL 9.4 上,我试图在一些连续的行上实现我将调用 "aggregate function" 的东西。示例:
输入数据:
recipe prod1 prod2 timestamp
0 5 4 2015-07-02 08:10:34.357
0 2 7 2015-07-02 08:13:45.352
0 7 0 2015-07-02 08:16:22.098
1 3 2 2015-07-02 08:22:14.678
1 9 4 2015-07-02 08:22:56.123
2 2 6 2015-07-02 08:26:37.564
2 1 7 2015-07-02 08:27:33.109
2 0 8 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210
期望的输出:
recipe prod1_sum prod2_avg timestamp_first timestamp_last
0 14 3.6666 2015-07-02 08:10:34.357 2015-07-02 08:16:22.098
1 12 3 2015-07-02 08:22:14.678 2015-07-02 08:22:56.123
2 3 7 2015-07-02 08:26:37.564 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210 2015-07-02 08:42:23.210
基本上,每个 "group" 连续行(当 table 在时间戳列上排序时)有一个输出行具有相同的 "recipe" 值。在输出中,prod1_sum是"group"中prod1的总和,prod2_avg是相同"group"中prod2的平均值,最后2列分别是第一列和组中的最后一个时间戳。显然有几个不同的组具有相同的 "recipe" 值,我确实希望每个组都有一个输出行。
目前,我有一种基于几个请求和数据库外部的大量数据处理来获取它的丑陋方法,我真的很想避免这种情况,但不值得展示。
我的问题确实是 "grouping" 行。我知道如何创建一个聚合函数来做我想做的事,如果我可以将它单独应用于每个组的话。我研究了 windows 函数,但似乎这会按配方对所有值进行分组,不符合我需要遵守的 "contiguous rows" 原则。
您可以使用以下查询:
SELECT recipe, SUM(prod1) AS prod1_sum,
AVG(prod2) AS prod2_avg,
MIN(timestamp) AS timestamp_first, MAX(timestamp) AS timestamp_last
FROM (
SELECT recipe, prod1, prod2, timestamp,
ROW_NUMBER() OVER (ORDER BY timestamp)
-
ROW_NUMBER() OVER (PARTITION BY recipe
ORDER BY timestamp) AS grp
FROM mytable ) t
GROUP BY recipe, grp
ORDER BY timestamp_first
这里的技巧是使用 ROW_NUMBER
window 函数来识别连续 recipe
值的孤岛:grp
计算字段正是这样做的。