结合 GROUP BY 对数组求和

Posted

技术标签:

【中文标题】结合 GROUP BY 对数组求和【英文标题】:Summing arrays in conjunction with GROUP BY 【发布时间】:2017-12-07 20:06:40 【问题描述】:

我有一些来自不同对象的周期性计数器数据(例如每秒一次),我希望将这些数据合并为每小时总数。

如果我用单独的列名来做,这很简单:

CREATE TABLE ts1 (
        id      INTEGER,
        ts      TIMESTAMP,
        count0  integer,
        count1  integer,
        count2  integer
);

INSERT INTO ts1 VALUES
        (1, '2017-12-07 10:37:48', 10, 20, 50),
        (2, '2017-12-07 10:37:48', 13, 7, 88),
        (1, '2017-12-07 10:37:49', 12, 23, 34),
        (2, '2017-12-07 10:37:49', 11, 13, 46),
        (1, '2017-12-07 10:37:50', 8, 33, 80),
        (2, '2017-12-07 10:37:50', 9, 3, 47),
        (1, '2017-12-07 10:37:51', 17, 99, 7),
        (2, '2017-12-07 10:37:51', 9, 23, 96);

SELECT id, date_trunc('hour', ts + '1 hour') nts, 
           sum(count0), sum(count1), sum(count2) 
    FROM ts1 GROUP BY id, nts;

id |         nts         | sum | sum | sum
----+---------------------+-----+-----+-----
  1 | 2017-12-07 11:00:00 |  47 | 175 | 171
  2 | 2017-12-07 11:00:00 |  42 |  46 | 277
(2 rows)

问题在于不同的对象有不同的计数(尽管每个特定对象的行——共享相同 ID 的行——都具有相同的计数)。因此我想使用一个数组。

对应的表格如下:

CREATE TABLE ts2 (
        id      INTEGER,
        ts      TIMESTAMP,
        counts  INTEGER[]
);

INSERT INTO ts2 VALUES
        (1, '2017-12-07 10:37:48', ARRAY[10, 20, 50]),
        (2, '2017-12-07 10:37:48', ARRAY[13, 7, 88]),
        (1, '2017-12-07 10:37:49', ARRAY[12, 23, 34]),
        (2, '2017-12-07 10:37:49', ARRAY[11, 13, 46]),
        (1, '2017-12-07 10:37:50', ARRAY[8, 33, 80]),
        (2, '2017-12-07 10:37:50', ARRAY[9, 3, 47]),
        (1, '2017-12-07 10:37:51', ARRAY[17, 99, 7]),
        (2, '2017-12-07 10:37:51', ARRAY[9, 23, 96]);

我查看了这个答案https://***.com/a/24997565/1076479 并了解了它的一般要点,但是当我尝试将它与按 id 和时间戳进行的分组相结合时,我无法弄清楚如何将正确的行汇总在一起。

例如,我得到了所有的行,而不仅仅是那些具有匹配 id 和时间戳的行:

SELECT id, date_trunc('hour', ts + '1 hour') nts, ARRAY(
        SELECT sum(elem) FROM ts2 t, unnest(t.counts)
            WITH ORDINALITY x(elem, rn) GROUP BY rn ORDER BY rn
        ) FROM ts2 GROUP BY id, nts;

 id |         nts         |    array
----+---------------------+--------------
  1 | 2017-12-07 11:00:00 | 89,221,448
  2 | 2017-12-07 11:00:00 | 89,221,448
(2 rows)

FWIW,我使用的是 postgresql 9.6

【问题讨论】:

【参考方案1】:

原始查询的问题在于您正在对所有元素求和,因为GROUP BY id, nts 在外部查询中执行。将CTE 与LATERAL JOIN 结合使用就可以了:

WITH tmp AS (
    SELECT 
        id, 
        date_trunc('hour', ts + '1 hour') nts, 
        sum(elem) AS counts
    FROM 
        ts2 
        LEFT JOIN LATERAL unnest(counts) WITH ORDINALITY x(elem, rn) ON TRUE 
    GROUP BY 
        id, nts, rn
)
SELECT id, nts, array_agg(counts) FROM tmp GROUP BY id, nts 

【讨论】:

以上是关于结合 GROUP BY 对数组求和的主要内容,如果未能解决你的问题,请参考以下文章

在雪花中结合 OBJECT_AGG 和 GROUP BY

关于case when结合group by用时的写法举例(转)

与 GROUP BY 结合的第一条记录

[MySQL]group by 与 having 结合函数 的统计技巧

SQL重复记录查询-count与group by having结合查询重复记录

如何在 MS SQL 中将 last_value 与 group by 结合使用?