28

PostgreSQLには同じ長さの2つの配列値があります。

{a,b,c}{d,e,f}

それらを組み合わせて

{{a,d},{b,e},{c,f}}

それを行う方法はありますか?

4

2 に答える 2

41

Postgres9.5以降

持っているarray_agg(array expression)

array_agganyarray)→anyarray

すべての入力配列を1つの高次元の配列に連結します。(入力はすべて同じ次元である必要があり、空またはnullにすることはできません。)

array_agg_mult()これは、以下に示すカスタム集計関数のドロップイン置換です。これはCで実装されており、かなり高速です。これを使って。

Postgres 9.4

複数の配列を並行してアンネストするROWS FROM構造または更新を使用します。unnest()それぞれの長さを変えることができます。あなたは(ドキュメントごとに)得ます:

[...]この場合の結果行の数は、最大の関数結果の数であり、小さい結果には一致するnull値が埋め込まれます。

このよりクリーンでシンプルなバリアントを使用してください。

SELECT ARRAY[a,b] AS ab
FROM   unnest('{a,b,c}'::text[] 
            , '{d,e,f}'::text[]) x(a,b);

Postgres9.3以前

シンプルなzip()

Postgres9.3以前の次のデモを検討してください。

SELECT ARRAY[a,b] AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
        , unnest('{d,e,f}'::text[]) AS b
    ) x;

結果:

  ab
-------
 {a,d}
 {b,e}
 {c,f}

並列にネストを解除するには、両方の配列に同じ数の要素が必要であることに注意してください。そうしないと、代わりにクロス結合が発生します。

次の場合は、これを関数にラップできます。

CREATE OR REPLACE FUNCTION zip(anyarray, anyarray)
  RETURNS SETOF anyarray LANGUAGE SQL AS
$func$
SELECT ARRAY[a,b] FROM (SELECT unnest($1) AS a, unnest($2) AS b) x;
$func$;

電話:

SELECT zip('{a,b,c}'::text[],'{d,e,f}'::text[]);

同じ結果。

多次元配列へのzip():

ここで、その新しい配列のセットを1つの2次元配列に集約する場合は、さらに複雑になります。

SELECT ARRAY (SELECT ...)

また:

SELECT array_agg(ARRAY[a,b]) AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
         ,unnest('{d,e,f}'::text[]) AS b
    ) x

また:

SELECT array_agg(ARRAY[ARRAY[a,b]]) AS ab
FROM  ...

すべて同じエラーメッセージが表示されます(9.1.5ページでテスト済み):

エラー:データ型text[]の配列型が見つかりませんでした

しかし、この密接に関連する質問の下で解決したので、これを回避する方法があります。
カスタム集計関数を作成します。

CREATE AGGREGATE array_agg_mult (anyarray) (
   SFUNC    = array_cat
 , STYPE    = anyarray
 , INITCOND = '{}'
);

そして、次のように使用します。

SELECT array_agg_mult(ARRAY[ARRAY[a,b]]) AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
        , unnest('{d,e,f}'::text[]) AS b
    ) x

結果:

{{a,d},{b,e},{c,f}}

追加のレイヤーに注意してくださいARRAY[]!それなしでただ:

SELECT array_agg_mult(ARRAY[a,b]) AS ab
FROM ...

あなたが得る:

{a,d,b,e,c,f}

これは他の目的に役立つかもしれません。

別の関数をロールします:

CREATE OR REPLACE FUNCTION zip2(anyarray, anyarray)
  RETURNS SETOF anyarray LANGUAGE SQL AS
$func$
SELECT array_agg_mult(ARRAY[ARRAY[a,b]])
FROM (SELECT unnest($1) AS a, unnest($2) AS b) x;
$func$;

電話:

SELECT zip2('{a,b,c}'::text[],'{d,e,f}'::text[]); -- or any other array type

結果:

{{a,d},{b,e},{c,f}}
于 2012-09-13T21:14:12.313 に答える
8

Erwinが言及した配列マルチアグリゲーションを使用して、長さが異なる配列に対して安全な別のアプローチを次に示します。

CREATE OR REPLACE FUNCTION zip(array1 anyarray, array2 anyarray) RETURNS text[]
AS $$
SELECT array_agg_mult(ARRAY[ARRAY[array1[i],array2[i]]])
FROM generate_subscripts(
  CASE WHEN array_length(array1,1) >= array_length(array2,1) THEN array1 ELSE array2 END,
  1
) AS subscripts(i)
$$ LANGUAGE sql;

regress=> SELECT zip('{a,b,c}'::text[],'{d,e,f}'::text[]);
         zip         
---------------------
 {{a,d},{b,e},{c,f}}
(1 row)


regress=> SELECT zip('{a,b,c}'::text[],'{d,e,f,g}'::text[]);
             zip              
------------------------------
 {{a,d},{b,e},{c,f},{NULL,g}}
(1 row)

regress=> SELECT zip('{a,b,c,z}'::text[],'{d,e,f}'::text[]);
             zip              
------------------------------
 {{a,d},{b,e},{c,f},{z,NULL}}
(1 row)

nullパディングではなく余分な部分を切り落としたい場合は、代わりに>=長さテストをに変更してください。<=

この関数は、配列に1以外の記述要素がある可能性があるというかなり奇妙なPostgreSQL機能を処理しませんが、実際には誰もその機能を実際に使用しません。たとえば、インデックスがゼロの3要素配列の場合:

regress=> SELECT zip('{a,b,c}'::text[], array_fill('z'::text, ARRAY[3], ARRAY[0]));
          zip           
------------------------
 {{a,z},{b,z},{c,NULL}}
(1 row)

wheras Erwinのコード、そのような配列で機能し、多次元配列(それらをフラット化することによって)でも機能しますが、長さが異なる配列では機能しません。

配列はPostgreSQLでは少し特殊で、多次元配列、構成可能なオリジンインデックスなどでは少し柔軟性があります。

9.4では、次のように書くことができます。

SELECT array_agg_mult(ARRAY[ARRAY[a,b])
FROM unnest(array1) WITH ORDINALITY as (o,a)
NATURAL FULL OUTER JOIN
unnest(array2) WITH ORDINALITY as (o,b);

これは、特に、並べ替えと結合を行うのではなく、関数を一緒にスキャンするための最適化が行われる場合に、はるかに優れています。

于 2013-07-29T06:03:39.940 に答える