14

いくつかのフィールドを選択しようとしていますが、そのうちの 1 つは、配列の各要素に2 つの値を含む配列である必要があります。各配列項目には、名前 (さまざまな文字) と ID (数値) を含める必要があります。(キーワードを使用して) 単一の値の配列を返す方法は知ってARRAYいますが、2 つの値を含むオブジェクトの配列を返す方法がわかりません。

クエリは次のようなものです

SELECT
    t.field1,
    t.field2,
    ARRAY(--with each element containing two values i.e. {'TheName', 1 })
FROM MyTable t

これを行う 1 つの方法は、値を型に選択してから、その型の配列を作成することです。問題は、関数の残りの部分が既に型を返していることです (つまり、ネストされた型を持つことになります。それでよろしいですか? もしそうなら、アプリケーション コードでこのデータをどのように読み取るのでしょうか? つまり、NPGSQL のような .Net データ プロバイダーを使用します)。 ?)

どんな助けでも大歓迎です。

4

2 に答える 2

12

ARRAY は同じ型の要素のみを保持できます

あなたの例は atextinteger値を表示します( を一重引用符で囲みません1)。通常、配列内で型を混在させることはできません。これらの値を配列に取得するには、composite type既に述べたように、その複合型の ARRAY を作成してから形成する必要があります。

またはjson、Postgres 9.2 以降jsonb、Postgres 9.4 以降、またはhstoreキーと値のペアのデータ型を使用できます


もちろん、 を にキャストしintegertext、2 次元テキスト配列を操作できます。以下のデモで配列入力の 2 つの構文バリアントを検討し、配列入力に関するマニュアルを参照してください。

克服すべき限界があります。ARRAY (キーと値から構築) を 2 次元配列に集約しようとすると、集約関数array_agg()またはARRAYコンストラクターでエラーが発生します。

ERROR:  could not find array type for data type text[]

ただし、それを回避する方法はあります。

キーと値のペアを 2 次元配列に集約する

PostgreSQL 9.1 とstandard_conforming_strings= on:

CREATE TEMP TABLE tbl(
 id     int
,txt    text
,txtarr text[]
);

この列txtarrは、INSERT コマンドの構文バリアントを示すためのものです。3 番目の行には、メタ文字がスパイクされています。

INSERT INTO tbl VALUES
 (1, 'foo', '{{1,foo1},{2,bar1},{3,baz1}}')
,(2, 'bar', ARRAY[['1','foo2'],['2','bar2'],['3','baz2']])
,(3, '}b",a{r''', '{{1,foo3},{2,bar3},{3,baz3}}'); -- txt has meta-characters

SELECT * FROM tbl;

単純なケース: 2 つの整数 (同じものを 2 回使用) を 2 次元の int 配列に集約します。

更新: カスタム集計関数を使用すると改善されます

ポリモーフィック型を使用すると、すべての基本型anyarrayで機能します。

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

電話:

SELECT array_agg_mult(ARRAY[ARRAY[id,id]]) AS x        -- for int
      ,array_agg_mult(ARRAY[ARRAY[id::text,txt]]) AS y -- or text
FROM   tbl;

ARRAY[]多次元配列にするための追加のレイヤーに注意してください。

Postgres 9.5 以降の更新

Postgres にはarray_agg()、配列入力を受け入れるバリアントが付属しており、上記のカスタム関数を次のように置き換えることができます。

マニュアル:

array_agg(expression)
...
1 つ高い次元の配列に連結された入力配列 (入力はすべて同じ次元でなければならず、空または NULL にすることはできません)

于 2012-02-03T19:24:40.303 に答える
5

あなたのアプリケーションについてもっと知識がなければ、あなたが必要とする結果にたどり着くことができないと思います。しかし、かなり遠くまで行くことができます。まず、次のROW関数があります。

# SELECT 'foo', ROW(3, 'Bob');
 ?column? |   row   
----------+---------
 foo      | (3,Bob)
(1 row)

そのため、行全体をセルにまとめることができます。タイプを作成することで、物事をより明確にすることもできます。

# CREATE TYPE person(id INTEGER, name VARCHAR);
CREATE TYPE
# SELECT now(), row(3, 'Bob')::person;
              now              |   row   
-------------------------------+---------
 2012-02-03 10:46:13.279512-07 | (3,Bob)
(1 row)

ちなみに、PostgreSQLはテーブルを作るたびに同名の型を作るので、このようなテーブルがすでにあれば型もある。例えば:

# DROP TYPE person;
DROP TYPE

# CREATE TABLE people (id SERIAL, name VARCHAR);
NOTICE:  CREATE TABLE will create implicit sequence "people_id_seq" for serial column "people.id"
CREATE TABLE

# SELECT 'foo', row(3, 'Bob')::people;
 ?column? |   row   
----------+---------
 foo      | (3,Bob)
(1 row)

peopleタイプと同じように使用した 3 番目のクエリを参照してください。

これは、次の 2 つの理由から、あなたが思っているほど役に立たない可能性があります。

  1. ネストされた行からデータを引き出すための便利な構文が見つかりません。

    何かが足りないかもしれませんが、この構文を使用している人はあまり見かけません。ドキュメントで目にする唯一の例は、行の値を引数として取り、それを使って何かを行う関数です。セルから行を取り出して、その一部に対してクエリを実行する例は見当たりません。この方法でデータをパッケージ化できそうですが、その後の分解は困難です。多くのストアド プロシージャを作成する必要があります。

  2. お使いの言語の PostgreSQL ドライバーは、行にネストされた行値データを処理できない場合があります。

    NPGSQL について話すことはできませんが、これは非常に PostgreSQL 固有の機能であるため、他のデータベースをサポートするライブラリではサポートされていません。たとえば、Hibernate は、行のセル値として格納されたオブジェクトのフェッチを処理できません。JDBC が Hibernate に有用な情報を提供できるかどうかさえ確信が持てないため、問題はかなり深刻になる可能性があります。

したがって、ここで行っていることは、多くの細かな点がなくても生活できるのであれば実行可能です。ただし、私が本当に誤解していない限り、それはずっと困難な戦いになるので、それを追求しないことをお勧めします.

于 2012-02-03T18:19:07.247 に答える