PostgreSQLの配列の配列

私はPostgreSQLの hstore 型でhastore(キー値型を効果的に){{key、value}、{key value}}の要素を持つ配列に変換する%%演算子を使用しています。

これらの平坦化されたhstoresの配列を返すとき、私はこのエラーが発生します:PostgreSQLが配列の配列をサポートしていないために、データ型text []

好奇心の観点から、誰もサポートされない理由を知っていますか?さらに重要なのは、このようなシナリオでは回避策がありますか?

現時点では、結果を文字列(コンマ区切り)に連結し、アプリケーション(C#とNPGSQL)側で解析しています。しかし、このアプローチはまったく正しいとは思えません。配列の配列やキー値の配列などを元の行に戻したいと思っています。

どうもありがとう。

3
タイトルには、仮前提があり、以下のこの答え:PostgreSQLは配列の配列をサポートしています。
追加された 著者 Peter Krauss,

3 答え

PostgreSQLには「配列の配列」サポートが限られています

マニュアルを参照

これは "配列の配列"の制限された形式です。 Pavel(答え)によれば、「多次元配列」という名前が付けられていますが、実際は行列なので、各次元に同じ数の要素が必要です。

この種の構造体を科学的アプリケーションの多次元デカルト座標と多次元デカルト座標に使用できますが、XMLやJSONデータのようなベクトルの任意のベクトルを格納することはできません。

注:よく知られている2次元(2D)同種配列は、数学行列。実際、 "PostgreSQLの制約付き多次元配列"データ型を動機とした行列の科学的応用、そして配列はこれらの種類の配列で関数の動作をします。 「3D配列」は「3Dマトリックス」、「4D配列」は「4Dマトリックス」などと考えてください。

例:

SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
---------------------
 {{1,2},{3,4},{5,6}}
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[[5,6]]); -- SAME RESULT

SELECT ARRAY[ARRAY[1,2],ARRAY[5,6]];
---------------
 {{1,2},{5,6}}

SELECT array_cat(ARRAY[ARRAY[1,2]],ARRAY[3]); -- ERROR1
SELECT ARRAY[ARRAY[1,2],ARRAY[4]];  -- ERROR2 

@Daniel_Lyonsの「なぜこれらがサポートされないのか」というコメントは、「配列の非一様な配列」に関するものです(上記のエラーケースを参照)。  上の ERROR1 :同じ次元の配列のみを連結できるため   ERROR2 :特定の次元のすべての配列は、行列のように同じ長さでなければなりません。

ビルドイン関数と演算子に関するもう一つの興味深いこと:PostgreSQLの "デフォルトの動作"は、単一の配列と要素のためのものです。標準的な array_append()のオーバーロードはありません。

SELECT array_append(ARRAY[1,2],5); -- now ok, 5 is a element
 {1,2,5}

SELECT array_cat(ARRAY[1,2], ARRAY[5,6]);
----------
 {1,2,5,6}

SELECT array_append(ARRAY[[1,2],[3,4]], ARRAY[5,6]); -- ERROR3 
SELECT array_append(ARRAY[1,2],ARRAY[5,6]); -- ERROR4

ERROR3 above: there are NO OVERLOAD to append "array element" (even 9.2 pg version). ERROR4 above: must use array_cat to "merge all in one array".

最後の array_cat の例の "マージの振る舞い"は興味深いものですが、配列の配列は生成されません。この結果を得るには array_cat(a1、ARRAY [a2])を使用し、

SELECT array_cat(ARRAY[1,2], ARRAY[ARRAY[5,6]]);  -- seems illogical...
---------------
{{1,2},{5,6}}

スパース行列

To avoid problems with スパース行列 and similar data structures, use the function below. It fills the remaining elements, setting then to NULL (or to any constant value).

 CREATE FUNCTION array_fillTo(anyarray,integer,anyelement DEFAULT NULL) 
 RETURNS anyarray AS $$
   DECLARE
     i integer;
     len integer;
     ret ALIAS FOR $0;
   BEGIN
     len = array_length($1,1);
     ret = $1;
     IF len<$2 THEN
         FOR i IN 1..($2-len) LOOP
           ret = ret || $3;
         END LOOP;
     END IF;
     RETURN ret;
   END;
 $$ LANGUAGE plpgsql IMMUTABLE;

最初の例に戻って、エラーを回避できるようになりました(ERROR1を参照)。

SELECT array_cat(ARRAY[ARRAY[1,2]],array_fillTo(ARRAY[3],2));
{{1,2},{3,NULL}}
15
追加された
JSONb とはあまり役に立ちませんが、時には可能です ARRAY of ROWs を使用するには ARRAY [ROW(g.f1、g.f2)] の例を参照してください。 postgresql.org/docs/current/static/queries-with.html "rel =" nofollow noreferrer "> pgガイドをご覧ください。
追加された 著者 Peter Krauss,
アンネストするには、 reduce_dim()を使用してください。
追加された 著者 Peter Krauss,

好奇心の観点から、誰もサポートされていない理由を知っていますか?

1つの一般的な答えは、配列が本質的に反関係であるためです。繰り返し値を削除すると、標準形式をどのように達成できますか。繰り返すグループの反復グループを持つことは、関係理論的観点からはかなり狂っているように思えます。

一般的に、関係の正しいことは、繰り返す値の表を抽出することです。だから、あなたがこのようなものをモデル化したなら、

CREATE TABLE users (
  id integer primary key,
  name varchar,
  favorite_colors varchar[],
  ...
);

あなたはこのように関係的に次のように再定義することをお勧めします:

CREATE TABLE users (
  id integer primary key,
  name varchar,
  ...
);

CREATE TABLE favorite_colors (
  user_id integer references users,
  color varchar
);

あるいは:

CREATE TABLE users (
  id integer primary key,
  name varchar,
  ...
);

CREATE TABLE colors (
  color varchar primary key
);

CREATE TABLE favorite_colors (
  user_id integer references users,
  color varchar references colors,
  primary key (user_id, color)
);

Hstoreは多くの機能をサポートしていますが、その多くはリレーショナルな世界観に容易に統合できます。あなたの問題を解決する最も簡単な方法は、 each 関数を使用してhstore値をリレーションに変換し、通常の値セットのように使うことだと思います。これは、とにかく他のデータベースに複数の値を持つことに対処する方法です。クエリと結果セットの操作です。

8
追加された
OPS! PostgreSQLは配列の配列をサポートしています(私の答えを見てください)...はい、読み込む前にいくつかのPostgreSQLの動作を理解していませんが、配列の均一性の制約があります。 JSONを一様な多次元配列にマップします。統一制約は、通常のフォームのようなものを保証しますが、正確には第1のものではありません。
追加された 著者 Peter Krauss,
@HannesLandeholm内部表現と関係表現を混同しています。すべてのデータベースには varchar があります。配列を持つものはほとんどありません。これは誰も配列として文字列を使用しないので意味があります。それらは原子値として扱われます。
追加された 著者 Daniel Lyons,
1つの一般的な答えは、配列が本質的に反リレーショナルであるためです。反復値を削除することは、第1の正規形をどのように達成するかです。ナンセンス。あなたは "繰り返す"という2つの異なる定義をミックスしています。 1つの定義は、非一意性/冗長性を意味します。もう1つは、一連のデータ(ある形式のベクトル)を持つことを意味します。文字列は文字の配列です。それが内部的に繰り返されている、重複している、またはそれが保持している価値の表現が貧弱であるということではありません。
追加された 著者 Bernhard Heijstek,

PostgreSQLは、代わりに多次元配列をサポートしています。配列は、リレーショナルデータベースでは非常に特殊な型であり、一般的なプログラミング言語に対しては少し制限があります。必要な場合は、行配列の回避策を使用できます。

postgres=# create table fx(a int[]);
CREATE TABLE
postgres=# insert into fx values(array[1,3,4]);
INSERT 0 1
postgres=# insert into fx values(array[6,7]);
INSERT 0 1
postgres=# select array_agg(row(a)) from fx;
            array_agg            
---------------------------------
 {"(\"{1,3,4}\")","(\"{6,7}\")"}
(1 row)
4
追加された