Начальный массив в функции для агрегирования многомерного массива - PullRequest
4 голосов
/ 23 марта 2012

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

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

9 голосов
/ 23 марта 2012

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[] (хотя и содержат другое количество измерений).

2 голосов
/ 23 марта 2012

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