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のような内部カウンターはどこにありますか?

注1:上記の解決策と質問は、「配列の各要素によってどのようにインデックスを作成しますか? 」と同じではありません。また、この関数は配列フィールドのテーブルインデックスではなく、分離された配列用であるため、「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

どちらのソリューションも、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()

パフォーマンス

これまでにここに示したすべてのクエリを使用して、1000intの配列で簡単なテストを実行しました。row_number()サブクエリのため、サブクエリ(〜7.5 ms)を除いて、すべてほぼ同じ(〜3.5 ms)を実行します。

更新:Postgres 9.4+

非標準のインデックス添え字を使用する場合を除き、WITH ORDINALITY代わりにnewを使用してください。

于 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 に答える