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