Начальный массив в функции для агрегирования многомерного массива

У меня есть таблица с массивами целых чисел.

Я хочу создать агрегатную функцию, которая будет возвращать 2-мерный массив со всеми строками вместе. Затем он передается 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 ответа

Postgres 9.5 или новее

... корабли с дополнительным вариантом агрегатной функции array_agg() который может объединять массивы в массив следующего более высокого измерения. Увидеть:

Он служит заменой настраиваемой функции агрегирования. array_agg_mult() ниже.

Postgres 9.4 или старше

Агрегатная функция для любого типа массива

С полиморфным типом 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[][] тот же тип, что и int[] для системы типов PostgreSQL. Глава о типах массивов в руководстве объясняет:

Текущая реализация также не обеспечивает заявленное количество измерений. Все массивы определенного типа элементов считаются одинаковыми, независимо от размера или количества измерений. Итак, объявляя размер массива или количество измерений в CREATE TABLE это просто документация; это не влияет на поведение во время выполнения.

n массив целых чисел эффективно представляет собой массив n-1 массивы целых чисел в PostgreSQL. Вы не можете сказать это по типу, который определяет только базовый элемент. Вы должны спросить 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[] (хотя и содержит другое количество измерений).

Использование встроенной функции 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}}
Другие вопросы по тегам