Unnest阵列一级

时间:2011-11-15 13:32:52

标签: arrays postgresql plpgsql

我想获取一个n维数组,并返回包含n-1维数组行的返回集。例如,取数组ARRAY[[1,2,3], [4,5,6], [7,8,9]]并返回集合{1,2,3}, {4,5,6}, {7,8,9}。使用unnest会返回集合1,2,3,4,5,6,7,8,9

我尝试从PostgreSQL 8.4中获取不需要的函数,这似乎就像我正在寻找的那样:

CREATE OR REPLACE FUNCTION tstng.unnest2(anyarray)
    RETURNS SETOF anyelement
    LANGUAGE plpgsql
    IMMUTABLE
    AS $$
    BEGIN
            RETURN QUERY SELECT $1[i]
                FROM generate_series(array_lower($1,1), array_upper($1,1)) i;
        END;
    $$;

但是,SELECT tstng.unnest2(ARRAY[[1,2,3], [4,5,6], [7,8,9]]);返回集合, ,(即:3个空行)。

我还发现SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[0];返回null,我认为这是我问题的根源。

3 个答案:

答案 0 :(得分:13)

解释

SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[0]

返回与

相同的内容
SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[17]

是NULL。我引用docs on that matter

  

默认情况下,数组维度的下限索引值为   设置为一个。

0在这里没有特别的意义。 此外,对于二维数组,您需要两个索引来获取基本元素。像这样:

SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[1][2]

结果:

2

您的信息的第一部分有点不清楚。

SELECT array_dims(ARRAY[[1,2,3], [4,5,6], [7,8,9]])

结果:

[1:3][1:3]

两个尺寸,每个尺寸包含3个元素(1到3个)(9个基本元素)。
如果您想要n-1尺寸,那么这是正确的结果:

SELECT ARRAY (SELECT unnest('{{1,2,3}, {4,5,6}, {7,8,9}}'::int[]))

结果:

{1,2,3,4,5,6,7,8,9}

那是一个维度。 unnest()每行始终生成一个基本元素。我不确定你究竟想要什么结果。你的例子只是另一个2维数组,缺少一组大括号......?

{1,2,3}, {4,5,6}, {7,8,9}

如果您想要数组,请尝试使用以下表示法:

SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[1:2]

结果:

{{1,2,3},{4,5,6}}

或者这个:

SELECT (ARRAY[[1,2,3], [4,5,6], [7,8,9]])[2:2][1:2]

结果:

{{4,5}}

展平结果(获取1D数组):

了解更多in the manual here

功能

后来的测试显示,这个plpgsql函数很多更快。需要Postgres 9.1或更高版本:

CREATE OR REPLACE FUNCTION unnest_2d_1d(ANYARRAY, OUT a ANYARRAY)
  RETURNS SETOF ANYARRAY AS
$func$
BEGIN
   FOREACH a SLICE 1 IN ARRAY $1 LOOP
      RETURN NEXT;
   END LOOP;
END
$func$  LANGUAGE plpgsql IMMUTABLE;

请参阅:

这是the function Lukas posted的改进和简化版本:

CREATE OR REPLACE FUNCTION unnest_2d_1d(anyarray)
  RETURNS SETOF anyarray AS
$func$
SELECT array_agg($1[d1][d2])
FROM   generate_subscripts($1,1) d1
    ,  generate_subscripts($1,2) d2
GROUP  BY d1
ORDER  BY d1
$func$  LANGUAGE sql IMMUTABLE;

对于Postgres版本< 8.4,默认情况下未安装array_agg()。首先创建它:

CREATE AGGREGATE array_agg(anyelement) (
 SFUNC=array_append,
 STYPE=anyarray,
 INITCOND='{}'
);

此外,generate_subscripts()尚未诞生。改为使用:

...
FROM   generate_series(array_lower($1,1), array_upper($1,1)) d1
    ,  generate_series(array_lower($1,2), array_upper($1,2)) d2
...

呼叫:

SELECT unnest_2d_1d(ARRAY[[1,2], [3,4], [5,6]]);

结果

{1,2}
{3,4}
{5,6}

SQL Fiddle.

答案 1 :(得分:7)

多维切片作为多维数组返回。这是unfst的修改版本,它将采用二维数组并返回一组1维数组。

更新:已修改为使用内置的array_agg聚合函数,该函数默认为8.4。 (http://www.postgresql.org/docs/9.2/static/functions-aggregate.html

<强>注意事项:

  • 它仅适用于二维数组(我应该重命名该函数以反映该限制)。
  • 如果您使用的是8.3(并且无法升级),则需要定义array_accum聚合,并将以下函数中的所有引用从array_agg更改为array_accum。 http://www.postgresql.org/docs/8.3/static/xaggr.html

<强>码

CREATE OR REPLACE FUNCTION unnest_multidim(anyarray)
RETURNS SETOF anyarray AS
$BODY$
  SELECT array_agg($1[series2.i][series2.x]) FROM
    (SELECT generate_series(array_lower($1,2),array_upper($1,2)) as x, series1.i
     FROM 
     (SELECT generate_series(array_lower($1,1),array_upper($1,1)) as i) series1 
    ) series2
GROUP BY series2.i
$BODY$
LANGUAGE sql IMMUTABLE;

<强>结果:

select unnest_multidim(array[[1,2,3],[4,5,6],[7,8,9]]);
unnest_multidim
----------------------
{1,2,3}
{4,5,6}
{7,8,9}
(3 rows)

现在,假设您想要轻松访问返回的其中一个数组。以下函数添加一个可选的索引参数,该参数将返回您提供的索引的嵌套数组,或者,如果您提供null,则将输出完整的“unnested”数组。

CREATE OR REPLACE FUNCTION unnest_multidim(anyarray, integer)
  RETURNS SETOF anyarray AS
$BODY$
SELECT array_agg($1[series2.i][series2.x]) FROM
  (SELECT generate_series(array_lower($1,2),array_upper($1,2)) as x, series1.i
  FROM 
    (SELECT CASE WHEN $2  IS NULL THEN
      generate_series(array_lower($1,1),array_upper($1,1)) 
      ELSE $2
      END as i) series1
  ) series2
GROUP BY series2.i
$BODY$
LANGUAGE sql IMMUTABLE;

<强>结果:

db=> select unnest_multidim(array[[1,2,3],[4,5,6],[7,8,9]],2);
 unnest_multidim 
-----------------
 {4,5,6}
(1 row)

db=> select unnest_multidim(array[[1,2,3],[4,5,6],[7,8,9]],NULL);
 unnest_multidim 
-----------------
 {1,2,3}
 {4,5,6}
 {7,8,9}
(3 rows)

答案 2 :(得分:0)

提醒一句:在postgres上使用array_agg&lt; 9命令可能会改变 PostgreSQL array_agg order 如果你打算使用unnested数组来查找argmax,这将破坏你的数据。