函数中的初始数组用于聚合多维数组

时间:2012-03-23 01:26:03

标签: arrays postgresql multidimensional-array aggregate-functions

我有一个包含整数数组的表。

我想创建一个聚合函数,它将返回一个包含所有行的二维数组。然后它被传递给plr以对其进行一些数学运算。

我有:

CREATE OR REPLACE
FUNCTION arrayappend(left int[][], right int[]) 
RETURNS int[] AS 
$BODY$
   SELECT $1 || $2 ;
$BODY$
LANGUAGE SQL;

CREATE AGGREGATE array_sum2 (int[])  (
    SFUNC     = arrayappend,
    STYPE     = int[][],
    INITCOND  = '{}'
);

但是返回类型是int[],而不是int[][]

如何使用空的二维整数数组初始化聚合?

2 个答案:

答案 0 :(得分:9)

Postgres 9.5或更新版

...附带了聚合函数array_agg()的其他变体,可以将数组聚合到下一个更高维的数组中。参见:

它可以作为下面自定义聚合函数array_agg_mult()的替代品。

Postgres 9.4或更早

任何数组类型

的聚合函数

使用polymorphic type anyarray它适用于所有类型的数组(包括integer[]):

CREATE AGGREGATE array_agg_mult (anyarray) (
   SFUNC     = array_cat
 , STYPE     = anyarray
 , INITCOND  = '{}'
);

正如@Lukas所提供的,不需要自定义函数arrayappend()。内置的array_cat()完成了这项工作。但是,这并没有解释为什么你的例子失败了,而@Lukas的答案中的那个失败了。相关的区别是@Lukas将数组嵌套到另一个数组array[d.a]

您错过了可以声明类型int[][]的错误假设。但你不能:int[][]与PostgreSQL类型系统的{strong>相同类型为int[]chapter on array types in the manual解释说:

  

当前实现不强制声明的数量   尺寸要么。特定元素类型的数组都是   被认为属于同一类型,无论大小或数量   尺寸。因此,声明数组的大小或维数   CREATE TABLE只是文档;它不会影响运行时行为。

n维整数数组实际上是PostgreSQL中n-1维整数数组的数组。您无法从仅定义基本元素的类型中分辨出来。您必须要求array_dims()获取具体信息。

演示:

SELECT array_agg_mult(arr1)               AS arr2  --> 2-dimensional array
     , array_agg_mult(ARRAY[arr1])        AS arr3  --> 3-dimensional array
     , array_agg_mult(ARRAY[ARRAY[arr1]]) AS arr4  --> 4-dimensional array
       -- etc.
FROM  (
   VALUES
      ('{1,2,3}'::int[])                          -- = 1-dimensional array
    , ('{4,5,6}')
    , ('{7,8,9}')
   ) t(arr1);

或者:

SELECT array_agg(arr2) AS arr3  --> 3-dimensional array
FROM  (
   VALUES
      ('{{1,2,3}}'::int[])      -- = 2-dimensional array
     ,('{{4,5,6}}')
     ,('{{7,8,9}}')
   ) t(arr2);

所有结果列具有相同的类型int[](即使包​​含不同数量的维度)。

答案 1 :(得分:2)

使用内置的array_cat函数有效。

CREATE AGGREGATE array_sum2 (int[])  (
    SFUNC     = array_cat,
    STYPE     = int[],
    INITCOND  = '{}'
);

试验:

select array_sum2(array[d.a]) from (select array[1,1,2,3] as a union select array[5,8,13,21] as a) d;
       array_sum2        
-------------------------
 {{1,1,2,3},{5,8,13,21}}