选择整数数组数组的每个第一个元素到数组

时间:2015-06-12 20:22:06

标签: arrays postgresql plpgsql

如何选择整数数组的每个第一个元素到数组?
{{1,2,3},{2,15,32},{5,16,14},...} - > {1,2,5,...}

3 个答案:

答案 0 :(得分:2)

由于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(),我们可以将其设置为一个集合,然后可以通过subselect将其输入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])。这当然适用于任意数量的输入数组。

答案 1 :(得分: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}'

请注意,arr中包含空/ NULL数组的行将从结果中删除 此外,虽然上述通常有效,但请使用此安全语法

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

详细说明:

答案 2 :(得分:0)

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)