web-dev-qa-db-ja.com

Postgresql:行を型にキャストする

私は読んだ: 複合型を使用して新しいテーブルを作成する

locationsというテーブルがあります。緯度でオブジェクトを表す。そして長い。座標。

別のテーブルで、タイプlocationsの列を宣言しました(ただの楽しみのために、賢くはありません)。

CREATE TABLE XXX (..., some_column locations, ...);

そして今、私はこれが何を意味するのか、そしてlocationsオブジェクトをそこに格納できるかどうかを自問しています。

そして、これが私がやろうとしたことです:

SELECT pg_typeof(ROW(x)) FROM locations x LIMIT 1;

recordを返します。これをlocationsにキャストしてみました。

SELECT ROW(x)::locations FROM locations X LIMIT 1;

これは

エラー:タイプレコードを場所にキャストできません

次に、locationsテーブルの列に基づいて複合型type_locationを定義して、型付きテーブルCREATE TABLE ... OF ...)を作成しました。それ。それでもROW(x)::locationsを実行できません。

最終的に、タイプXXX(またはtype_location)のテーブルlocationsに格納する値を取得しようとしていますが、私の推論が誤っている部分がわかりません。

PS:私はこの構造を使用して健全なデータベース設計を作成しようとしているのではなく、単にPostgresqlとその型システムをいじるだけです。

2
VH-NZZ

そして今、私はこれが何を意味するのか、そしてそこに場所オブジェクトを保存できるかどうかを自問しています。

はい、できます。 (しかし、そのための優れたユースケースは多くありません。)

これは、あなたが思っているようには見えません。

SELECT ROW(x)::locations FROM locations X LIMIT 1;

xはすでに行タイプです。それをROW(x)にラップすることで、レコードを作成します含むlocationsタイプの列。これは、そのままでは行タイプlocationsにキャストできません。他の何か。代わりに使用:

_SELECT x::locations FROM locations x LIMIT 1;
_

...キャストは冗長です。これだけ:

_SELECT x FROM locations x LIMIT 1;
_

ただし、、同じ名前の列がある場合は_"x"_、これは列名に解決されます。 neverが列名として表示されるテーブルエイリアスを選択するか、これを使用して確認します。

_SELECT (x.*)::locations FROM locations x LIMIT 1;
_

現在、キャストはnot冗長です。Postgresは、そうでなければ_x.*_または_(x.*)_を列のリストに拡張するためです。マニュアル here および here をお読みください。


またちょうど:

_SELECT pg_typeof(x) FROM locations x LIMIT 1;
_

の代わりに:

SELECT pg_typeof(ROW(x)) FROM locations x LIMIT 1;

余談ですが、 ROWコンストラクタ は列名を保持せず、常に匿名レコードを生成します(難しい方法を見つけたため)。

_SELECT ROW(x)::locations FROM locations X LIMIT 1;
_

関連:

2

私もこの1週間、タイプとキャストをいじくり回していて、あなたの質問が大好きです。ここにちょっとしたトリックがあります(?)

create table state_crunched
     (data state);


-- table_name::table_name or table_name::text cast a row/compound type to a (csv,ish,"format like this")    insert into state_crunched 
    select state::state from state; 

私の場合、サンプルテーブルは状態です。

CREATE TABLE IF NOT EXISTS api.state (
    id uuid DEFAULT gen_random_uuid(),
    "name" citext,
    abbreviation citext,
    population bigint,
    total_sq_miles real,
    percent_land text
);

今回のケースでは、テーブルごとに1つ以上のカスタムタイプを実装しています。タイプ/フォーマットに従って行をアーカイブできると便利です。

create table state_crunched
     (format_name text,
     data state);

試してみましたが、列タイプとして匿名レコードを作成する方法がわかりません。 (table :: tableシリアル化トリックの後にテキストなどとして保存する以外は。)アーカイブのためにレコードを行に保存することを考えています。おそらく、各ソースアーカイブにレプリケーションと履歴テーブルを使用する方が良いでしょう。しかし、あなたのように、私は利用可能な機能の範囲に頭を抱えています。したがって、上のスケッチテーブルでは、タイプ名によってデータをアンパックしてレコード構造に戻す方法がわかります。 CREATE CASTで定義された::キャストと、展開を処理する関数を使用できます。または、少なくともそれは私が考えていたものです。私はその仕事をする方法を知りません。

「なぜテーブルに複数の複合型があり、それ自体はすでに複合型であるのか?」.

CREATE TYPE api.state_v1 AS
(
    "name" citext,
    population bigint,
    total_sq_miles real,
    percent_land text,
    statehood_year integer,
);


CREATE TYPE api.state_v2 AS
(
    id uuid,
    "name" citext,
    abbr citext,
    population bigint,
    total_sq_miles real,
    percent_land real,
    statehood_year smallint,
    capital citext
);

私たちの場合、CRUD作業がPostgres以外で行われる分散システムがあります。次に、データはPostgresにプッシュされ、集計と分析が行われます。現場の「クライアント」アプリケーションは、更新の間に大幅に遅れることがあります。サイトが最新のリリースから数か月遅れることは完全に可能です。つまり、INSERTなどの操作は、数か月前のPostgresの構造に基づいています。この状況では、多くの人がORMまたはさまざまなタイプの入力フォーマットを現在の構造に変換するための集中化されたレイヤーを持っていると思います。さて、Postgres is集中システムなので、コードはそこに行きます。アイデアは、state_v1 []やstate_v2 []のような特定の形式の行の配列を受け入れるINESRT処理関数を持つことです。次に、サーバー側の関数は、受信した配列データのネストを解除し、必要に応じてそれをマッサージし、テーブルに挿入します。基になるテーブルに列名が追加、削除、名前変更、または再入力されている場合、関数は古い形式を新しい形状に変換することを処理できます。

アイデア、情報、トリックを思いついたら興味を持って見ていきます。

0
Morris de Oryx