将相同长度的数组记录求和到新数组中

时间:2019-04-19 03:47:45

标签: sql postgresql

我有一堆记录,每个记录都有一个数值数组。

这些值必须位于数组中,因为不能保证整个数据集中的元素数量都是相同的,即我不能拆分为一致的列。

但是,在一组“记录”中,每个数组的元素位置和长度的重要性相同,我需要对其进行汇总。

例如:

SELECT * FROM day_summary WHERE group_code=1;

summary_date | vals
-------------|--------
2019-04-17   | {0,3,4}
2019-04-18   | {1,3,2}
2019-04-19   | {7,5,1}

我需要汇总为:

SELECT extract('month' from summary_date) month,
    what_do_i_do(vals)
FROM day_summary
WHERE group_code=1
GROUP BY 1;

month  | vals
-------|--------
4      | {8,11,7}

(posgresql 9.6)

4 个答案:

答案 0 :(得分:2)

如果您需要做很多事情,可以为此创建一个自定义聚合:

create or replace function array_sum(p_one int[], p_two int[])
  returns int[]
as
$$
  select array_agg(coalesce(x1.val,0) + coalesce(x2.val,0))
  from unnest(p_one) with ordinality as x1(val, ix)
    full join unnest(p_two) with ordinality as x2(val, ix) on x1.ix = x2.ix;
$$
language sql
stable;

create aggregate array_sum_agg(int[]) 
(  
  sfunc = array_sum,
  stype = int[],
  initcond = '{}'
);

然后您可以像这样使用它:

SELECT extract('month' from summary_date) as month,
       array_sum_agg(vals)
FROM day_summary
WHERE group_code=1
GROUP BY 1;

在线示例:https://rextester.com/XWD31187

答案 1 :(得分:1)

您可以使用unnest进行此操作以允许聚合:

select month, array_agg(val ORDER BY pos) FROM
  ( 
    SELECT extract('month' from summary_date) as month, s.pos, sum(s.val) as val
    FROM day_summary,
    LATERAL unnest(day_summary.vals) WITH ORDINALITY s(val, pos)
    GROUP BY month, s.pos
   ) x
GROUP by month;

如果阵列很大或很多,则可能效果不佳。我最近一直在研究Postgres扩展,它将对此简化(此处:https://github.com/tarkmeper/numpgsql)以支持直接在数组上进行数值计算。它包括允许求和汇总直接用于数字数组类型(但是您需要具有构建和安装扩展的能力)。

答案 2 :(得分:0)

我认为您需要这样

从(作为调节剂)中选择SUM(体积);

答案 3 :(得分:0)

您可以尝试使用generate_subscripts

的另一种方法

架构(PostgreSQL v9.5)

CREATE TABLE T(
    summary_date date,
    val integer[]
);



INSERT INTO T VALUES ('2019-04-17','{0,3,4}');
INSERT INTO T VALUES ('2019-04-18','{1,3,2}');
INSERT INTO T VALUES ('2019-04-19','{7,5,1}');

查询#1

SELECT m,array_agg(val ORDER BY rn)
FROM (
  SELECT  extract('month' from tt.summary_date) m,sum(tt.val[rn]) val,rn
  FROM  T tt
  CROSS JOIN generate_subscripts(tt.val, 1) AS rn
  GROUP BY extract('month' from tt.summary_date),rn
) t1
 group by m;

| m   | array_agg |
| --- | --------- |
| 4   | 8,11,7    |

View on DB Fiddle