PostgreSQL имеет ограниченную поддержку "массива массивов"
см. Руководство
Это ограниченная форма "массива массивов". Как говорит Павел (ответ), он называется «многомерный массив», но на самом деле является матрицей, поэтому в каждом измерении должно быть одинаковое количество элементов.
Вы можете использовать такую структуру для отображения многомерных и разнородных декартовых координат в научных приложениях, но не для хранения произвольных векторов векторов, таких как данные XML или JSON.
ПРИМЕЧАНИЕ. Хорошо известная двумерная (2D) однородная матрица представляет собой математическую матрицу . Фактически, научные применения матрицы, которые мотивировали тип данных «Ограниченный многомерный массив PostgreSQL», и поведение функций массива с такими массивами. Подумайте о «3D-массиве» как «3D-матрице», «4D-массиве» как «4D-матрице» и т. Д.
Примеры:
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
---------------------
{{1,2},{3,4},{5,6}}
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[[5,6]]); -- SAME RESULT
SELECT ARRAY[ARRAY[1,2],ARRAY[5,6]];
---------------
{{1,2},{5,6}}
SELECT array_cat(ARRAY[ARRAY[1,2]],ARRAY[3]); -- ERROR1
SELECT ARRAY[ARRAY[1,2],ARRAY[4]]; -- ERROR2
Комментарии @Daniel_Lyons о том, «почему они не поддерживаются», касаются «неоднородных массивов массивов» (см. Случаи ошибок выше).
ERROR1
выше: потому что можно объединять массивы только одного размера
ERROR2
выше: все массивы для определенного измерения должны иметь одинаковую длину, как матрица.
Еще одна любопытная вещь в отношении встроенных функций и операторов: «поведение по умолчанию» в PostgreSQL предназначено для отдельных массивов и элементов. Там нет перегрузки для стандартных array_append()
,
SELECT array_append(ARRAY[1,2],5); -- now ok, 5 is a element
{1,2,5}
SELECT array_cat(ARRAY[1,2], ARRAY[5,6]);
----------
{1,2,5,6}
SELECT array_append(ARRAY[[1,2],[3,4]], ARRAY[5,6]); -- ERROR3
SELECT array_append(ARRAY[1,2],ARRAY[5,6]); -- ERROR4
ERROR3
выше: НЕТ ПЕРЕГРУЗКИ, чтобы добавить «элемент массива» (даже версия 9,2 pg).
ERROR4
выше: необходимо использовать array_cat для «объединения всех в один массив».
"Поведение слияния" в последнем примере array_cat
является любопытным, а не созданным массивом массивов. Используйте array_cat(a1, ARRAY[a2])
для достижения этого результата,
SELECT array_cat(ARRAY[1,2], ARRAY[ARRAY[5,6]]); -- seems illogical...
---------------
{{1,2},{5,6}}
Разреженная матрица
Чтобы избежать проблем с разреженной матрицей и аналогичными структурами данных, используйте функцию ниже. Он заполняет остальные элементы, устанавливая затем значение NULL (или любое постоянное значение).
CREATE or replace FUNCTION array_fillTo(
p_array anyarray, p_len integer, p_null anyelement DEFAULT NULL
) RETURNS anyarray AS $f$
SELECT CASE
WHEN len=0 THEN array_fill(p_null,array[p_len])
WHEN len<p_len THEN p_array || array_fill($3,array[$2-len])
ELSE $1 END
FROM ( SELECT COALESCE( array_length(p_array,1), 0) ) t(len)
$f$ LANGUAGE SQL IMMUTABLE;
PS: пожалуйста, отредактируйте этот ответ, чтобы добавить исправления / оптимизации, это Вики!
Возвращаясь к первым примерам, теперь мы можем избежать ошибок (см. ERROR1),
SELECT array_cat(ARRAY[ARRAY[1,2]],array_fillTo(ARRAY[3],2));
-- {{1,2},{3,NULL}}
SELECT array_cat(
ARRAY[ARRAY[1.1::float,2.0]],
array_fillTo(ARRAY[]::float[],2,0::float)
);
-- {{1.1,2},{0,0}}
SELECT array_fillto(array['Hello'],2,'');
-- {Hello,""}
ПРИМЕЧАНИЕ о старом array_fillTo ()
array_fill()
становится встроенной функцией с PostgreSQL v8.4, для v8.3 или старше:
CREATE FUNCTION array_fillTo(anyarray,integer,anyelement DEFAULT NULL)
RETURNS anyarray AS $$
DECLARE
i integer;
len integer;
ret ALIAS FOR $0;
BEGIN
len = array_length($1,1);
ret = $1;
IF len<$2 THEN
FOR i IN 1..($2-len) LOOP
ret = ret || $3;
END LOOP;
END IF;
RETURN ret;
END;
$$ LANGUAGE plpgsql IMMUTABLE;