5

这是我的(也许对你来说很常见)未优化的解决方案:

未优化内部函数的 PG 问题的解决方法:

CREATE FUNCTION unnest_with_idx(anyarray)
RETURNS TABLE(idx integer, val anyelement) AS
$$ 
   SELECT generate_series(1,array_upper($1,1)) as idx, unnest($1) as val;
$$ LANGUAGE SQL IMMUTABLE;

测试:

SELECT idx,val from unnest_with_idx(array[1,20,3,5]) as t;

但是,正如我所说,未优化的. 我不敢相信(!!)PostgreSQL 没有数组的内部索引......?但是在这种情况下,问题是如何直接访问这个索引,在哪里有类似 GIN 的内部计数器?

NOTE1:上面的解决方案和问题与“如何为数组的每个元素创建索引? ”不同。也与“可以 PostgreSQL 索引数组列吗? ”不同,因为该函数是针对独立数组的,而不是针对数组字段的表索引。


注意2(在回答后编辑):“数组索引”(更流行的术语)或“数组下标”或“数组计数器”是我们可以在语义路径中使用的术语,以将“内部计数器”、累加器指向下一个数组物品。我看到没有 PostgreSQL 命令提供对这个计数器的直接访问。作为generate_series()函数,该generate_subscripts()函数是一个序列生成器,性能(最好但)几乎相同。另一方面row_number(),函数提供了对“行的内部计数器”的直接访问,但它是关于行的,而不是关于数组的,不幸的是性能更差。

4

2 回答 2

7

PostgreSQL确实提供了专门的函数来生成数组下标

WITH   x(a) AS ( VALUES ('{1,20,3,5}'::int[]) )
SELECT generate_subscripts(a, 1) AS idx
      ,unnest(a) AS val
FROM   x;

实际上,它与@Frank 的查询几乎相同,只是没有子查询。
此外,它适用于不以 . 开头的下标1

任何一种解决方案都只适用于一维数组!(可以很容易地扩展到多个维度。)

功能:

CREATE OR REPLACE FUNCTION unnest_with_idx(anyarray) 
RETURNS TABLE(idx integer, val anyelement) LANGUAGE SQL IMMUTABLE AS
$func$
  SELECT generate_subscripts($1, 1), unnest($1);
$func$;

称呼:

SELECT * FROM unnest_with_idx('{1,20,3,5}'::int[]);

还要考虑:

SELECT * FROM unnest_with_idx('[4:7]={1,20,3,5}'::int[]);

有关此相关问题中数组下标的更多信息。

如果你真的想要规范化的下标(从 1 开始),我会使用:

SELECT generate_series(1, array_length($1,1)) ...

这几乎就是您已经拥有的查询,只是使用array_length()而不是array_upper()- 会因非标准下标而失败。

表现

我对一个包含 1000 个 int 的数组进行了快速测试,到目前为止所有查询都在这里显示。由于子查询,它们的性能大致相同(~ 3,5 ms) - 除了row_number()子查询(~ 7,5 ms) - 正如预期的那样。

更新:Postgres 9.4+

除非您使用非标准索引下标进行操作,否则请使用 newWITH ORDINALITY代替:

于 2012-09-03T14:43:42.300 回答
1

row_number()有效:

SELECT 
    row_number() over(), 
    value
FROM (SELECT unnest(array[1,20,3,5])) a(value);

那么优化后的函数为

CREATE OR REPLACE FUNCTION unnest_with_idx(anyarray) 
RETURNS table(idx integer, val anyelement) AS $$ 
  SELECT (row_number() over())::integer as idx, val
  FROM (SELECT unnest($1)) a(val);
$$ LANGUAGE SQL IMMUTABLE;
于 2012-09-03T12:27:33.890 回答