对自定义聚合函数填充NULL到最大长度的数组

时间:2014-09-24 13:13:45

标签: sql arrays postgresql aggregate-functions

问题How to use array_agg() for varchar[]的回答,

我们可以创建一个自定义聚合函数来聚合Postgres中的n维数组,如:

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

约束是值必须共享相同的数组范围和相同的长度,处理空值和不同的长度不起作用。

答案:

  

没有办法,数组类型不允许这样的   Postgres不匹配。您可以使用NULL值填充数组   所有维度都有匹配的范围。

我有像

这样的行
------ arrayfield

-----  {1},
-----  {},
-----  {abc}

array_agg_mult(ARRAY[arrayfield]) AS customarray

我期待像{{1},NULL,{abc}}

这样的汇总结果

但它会抛出

ERROR:  cannot concatenate incompatible arrays
DETAIL:  Arrays with differing element dimensions are not compatible for concatenation.

我们是否可以在自定义函数中添加填充值?

我发现问题是当数组 length 不同时。 {a},{null},{1}将汇总,但{a,b},{},{1}不会。

所以我需要一个查询,我可以在现有数组中添加NULL元素。

一种解决方案是始终追加两个NULL(2是该字段中的最大长度)array_cat(arr, ARRAY[NULL,NULL])并将数组修剪为长度2:

   {1}   --> {1,NULL,NULL}     --> {1,NULL}
   {NULL}  --> {NULL,NULL,NULL}  --> {NULL,NULL}
   {abc, def}  --> {abc,def,NULL,NULL}  --> {abc, def} 

但我无法弄清楚语法

1 个答案:

答案 0 :(得分:1)

使用此相关答案中定义的自定义聚合函数array_agg_mult()

您的预期结果是不可能的:

{{1},NULL,{abc}}

必须是:

{{1},{NULL},{abc}}

具有0或1个数组元素的简单案例

对于简单的情况,只需替换空数组: 您可以通过以下方式实现这一目标:

WITH t(arr) AS (
    VALUES
      ('{1}'::text[])
     ,('{}')
     ,('{abc}')
   )
SELECT array_agg_mult(ARRAY[CASE WHEN arr = '{}' THEN '{NULL}' ELSE arr END])
FROM   t;

n个元素的动态填充

使用array_fill()填充NULL元素的数组,最大长度为:

SELECT array_agg_mult(ARRAY[
         arr || array_fill(NULL::text
                         , ARRAY[max_elem - COALESCE(array_length(arr, 1), 0)])
       ]) AS result
FROM   t, (SELECT max(array_length(arr, 1)) AS max_elem FROM t) t1;

仍然只适用于 1维基本数组。

解释

  • 子查询t1计算基本1维数组的最大长度。
  • COALESCE(array_length(arr, 1), 0)计算此行中数组的长度 对于COALESCE0默认为NULL
  • 使用array_fill()生成长度差异的填充数组。
  • 使用arr
  • 将其附加到||
  • 与上面的array_agg_mult()进行汇总。

SQL Fiddle.演示全部 SQL小提琴中的输出具有误导性,因此我将结果转换为文本。