如何仅对连续的行应用聚合函数?

时间:2015-07-02 06:26:07

标签: sql postgresql aggregate-functions window-functions

在PostgreSQL 9.4上,我试图实现我称之为"聚合功能"在一些连续的行上。例如:

输入数据:

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

基本上,每个"组的一个输出线"连续行(当表在时间戳列上排序时)与相同的"配方"值。在输出中,prod1_sum是"组"中prod1的总和,prod2_avg是同一"组"中prod2的平均值,最后2列分别是第一列和最后一列组中的时间戳。显然,有几个不同的组具有相同的"配方"值,我确实想要每个输出行。

目前,基于数据库之外的多个请求和大量数据处理,我有一种丑陋的方式来获取此信息,这是我真正想避免的,而且不值得展示。

我的问题确实是"分组"的行。如果我可以单独将它应用于每个组,我知道如何创建一个可以做我想要的聚合函数。我已经查看了windows函数,但似乎这会按照配方对所有值进行分组,而不是符合"连续的行"原则我需要尊重。

1 个答案:

答案 0 :(得分:4)

您可以使用以下查询:

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窗函数来识别连续recipe值的孤岛:grp计算字段就是这样。

Demo here