Выберите каждый первый элемент массива целочисленных массивов в массив
Как выбрать каждый первый элемент массива целочисленных массивов в массив?{{1,2,3},{2,15,32},{5,16,14},...}
-> {1,2,5,...}
3 ответа
Так как PostgreSQL позволит запрашивать срез за пределами размера массива, и при условии, что никогда не будет более 999 подмассивов, мы можем использовать это чудовище
WITH data AS (
SELECT array[array[1,2,3], array[2,15,32], array[5,16,14]] as arr)
SELECT array_agg(arr)
FROM (SELECT unnest(arr[1:999][1]) as arr from data) data2;
Вы можете, конечно, сделать константу 999 больше, если это необходимо, это просто случайное большое число, которое я добавил туда.
Причина, по которой это так сложно, заключается в том, что если бы вы использовали только arr[1:999][1]
вы все равно получите двумерный массив, но только с первыми элементами. В этом случае {{1}, {2}, {5}}
, Если мы используем unnest()
мы можем сделать это в набор, который затем может быть подан в array_agg()
через подвыбор.
Было бы неплохо использовать array_agg(unnest(arr[1:999][1]))
но функция агрегации не любит множества, и я не знаю, есть ли способ конвертировать ее на лету.
Вы также можете использовать фактическую длину массива, но это может привести к ненужным вычислениям
SELECT unnest(arr[1:array_length(arr, 1)][1]) as arr from data
Заметка
Если массивы могут быть неопубликованы одним уровнем, вы можете просто проиндексировать массивы, а затем использовать array_agg()
преобразовать его обратно в массив с гораздо более простым синтаксисом
WITH data AS
(SELECT array[1,2,3] as arr
UNION ALL SELECT array[2,15,32] as arr
UNION ALL SELECT array[5,16,14] as arr)
SELECT array_agg(arr[1]) from data;
CTE там только для входных данных, фактическое мясо является array_agg(arr[1])
, Это, конечно, будет работать для любого количества входных массивов.
Учитывая эту таблицу:
CREATE TEMP TABLE arrtbl (
arrtbl_id serial PRIMARY KEY
, arr int[]
);
Примерные значения:
INSERT INTO arrtbl (arr)
VALUES
('{{1,2,3},{2,15,32},{5,16,14}}')
, ('{{17,22},{1,15},{16,14}}') -- dimensions can vary across rows!
, ('{}')
, (null);
Это сделало бы работу для всех строк:
SELECT arrtbl_id, array_agg(a) AS a1
FROM arrtbl t
, unnest(t.arr[-2147483648:2147483647][1]) a
GROUP BY 1;
Зачем [-2147483648:2147483647]
?
Результат:
arrtbl_id | a1
----------+-----------
1 | '{1,2,5}'
2 | '{17,1,16}'
Обратите внимание, что строки с пустым массивом / NULL в arr
исключены из результата.
Кроме того, хотя вышеуказанное обычно работает, лучше использовать этот безопасный синтаксис:
SELECT arrtbl_id, array_agg(a.a ORDER BY a.ordinality)
FROM arrtbl t
LEFT JOIN LATERAL unnest(t.arr[-2147483648:2147483647][1]) WITH ORDINALITY a ON true
GROUP BY 1;
Результат:
arrtbl_id | a1
----------+-----------
1 | '{1,2,5}'
2 | '{17,1,16}'
3 | null
4 | null
Детальное объяснение:
Plpgsql решение:
create or replace function first_elements(arr anyarray)
returns int[] language plpgsql
as $$
declare
i int;
res int[];
begin
for i in 1..array_length(arr, 1) loop
res = array_append(res, arr[i][1]);
end loop;
return res;
end $$;
with test as (
select array[array[1,2,3], array[2,15,32], array[5,16,14]] a
union
select array[array[101,0], array[102,0]] a
)
select first_elements(a) from test;
first_elements
----------------
{1,2,5}
{101,102}
(2 rows)