Как отсортировать двухмерный массив int в PostgreSQL?
{{5,23}, {8,45}, {1,12}}
Я хочу отсортировать этот массив в соответствии с первым элементом каждого элемента подмассива, как;
{{1,12}, {5,23}, {8,45}}
Как я могу это сделать?
Редактировать:
Этот код работает;
create or replace function arraysortingaccordingfirstindexofsubarrayelements()
returns void as $$
declare samplearraydata integer[][];
declare sortedarraydata int[][];
begin
samplearraydata:=ARRAY[[5,8], [1,6],[3,9]];
EXECUTE 'CREATE TEMP TABLE temptable (
firstindex integer,
secondindex integer
) on commit drop;';
WITH
data as (select samplearraydata as arr)
insert into temptable select
arr[i][1],
arr[i][2] FROM data,
generate_subscripts((SELECT arr FROM data), 1) i
order by 1;
sortedarraydata:=(SELECT array_agg_mult(ARRAY[ARRAY[y.firstindex, y.secondindex]])) FROM temptable y;
raise notice '%', sortedarraydata;
end;
$$ language plpgsql;
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
CREATE TEMP TABLE arrtbl (
firstindex integer,
secondindex integer
) on commit drop;
Кредиты Эрвину:)
2 ответа
Postgres 9.5 или новее
корабли с вариантом array_agg()
который служит заменой для произвольной функции агрегирования array_agg_mult()
ниже - и значительно быстрее. Руководство:
Function Argument Type(s) Return Type array_agg(expression) any array type same as argument data type Description input arrays concatenated into array of one higher dimension (inputs must all have same dimensionality, and cannot be empty or NULL)
Postgres 9.4 или старше
Агрегатная функция
Встроенная агрегатная функция array_agg()
в настоящее время (Postgres 9.4) работает только для входных данных не массивов. Поскольку мы собираемся собирать массивы, нам нужна настраиваемая функция агрегирования, как подробно описано в следующем ответе:
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Доступ к массиву
Требуется базовое понимание синтаксиса массива / как получить доступ к массивам. Прочтите эту главу руководства, если вы еще не там.
запрос
Затем, основываясь на той же настройке, что и этот более ранний ответ сегодня (вы можете прочитать и этот):
SELECT arrtbl_id
, array_agg_mult(arr[i:i][lo2:up2] ORDER BY arr[i:i][lo2])
FROM (SELECT arrtbl_id, arr
, array_lower(arr, 2) AS lo2
, array_upper(arr, 2) AS up2
FROM arrtbl) t
, generate_subscripts(t.arr, 1) i
GROUP BY 1;
объяснение
Вычислить нижнюю и верхнюю границу для второго измерения массива в базовой таблице, это дешевле, чем повторять его для каждого среза массива.
Я не просто начинаю с индекса 1, чтобы охватить возможный угловой случай. Postgres допускает нестандартные подписки на массивы:
LATERAL
присоединиться к основному столуgenerate_subscripts(arr,1)
чтобы получить первый индекс для каждого подмассива (независимо от того, сколько измерений).Выражение
arr[i:i][lo2:up2]
(или простоarr[i:i][:]
в стр 9.6+) возвращает каждый срез массива, сохраняя размеры. Это работает для любого количества элементов и размеров (больше 1).Выражение
arr[i:i][lo2]
возвращает первый срез в каждом срезе массива, который определяет порядок сортировки. Для строго 2-х мерных массивов вы можете использоватьarr[i][lo2]
вернуть первый элемент каждого среза, но первый работает для любой размерности больше 1.Агрегировать с
array_agg_mult()
который с радостью принимает значения соответствующего измерения (все хорошо встает на свои места).
Начиная с Postgres 9.4, если вы можете разбить ваш двумерный массив на два одномерных массива, вы можете использовать оператор
unnest(anyarray, anyarray [, ...])
Пример:
SELECT * FROM unnest(ARRAY[6,4,3,5], ARRAY[64,2,1,-1], ARRAY[45,2,4,6]) ORDER BY 1
Вернуть:
4 2 2
3 1 4
5 -1 6
6 64 45
Если вы хотите отсортировать по третьему элементу, вы должны изменить
... ORDER BY 3