PostgreSQL:生成された列


16

PostgreSQLは生成列をサポートしていますか?仮想列とも呼ばれます。私はコラムについて話してませんIDENTITY

この注目すべき機能に関する情報は見つかりませんが、SQL ServerおよびMariaDB&MySQLの最新バージョンで利用できることは知っています。

この機能はSQL:2003標準で言及されており、2006年頃にPostgreSQLフォーラムで議論が行われましたが、この問題に関して実質的なものは見つかりません。

SOについてはいくつかの議論がありますが、現在はかなり古いため、古くなっている可能性があります。


2
SOに関する2012年のこの関連する回答は役に立つかもしれません:stackoverflow.com/questions/11165450/…まだ有効です。
アーウィンブランドステッター

@ErwinBrandstetter申し訳ありませんが、このコメントを見逃しました。これは便利なトリックです。ありがとう。
マンゴー

回答:


17

これがあなたの望むものかどうかはわかりませんが、postgresql では属性表記row.full_nameと関数表記full_name(row)は同等です。

それはテーブルを取ることを意味します

CREATE TABLE people (
  first_name text,
  last_name text
);

および関数:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

次のように呼び出します:

select full_name from people

それはあなたが必要なものですか?

速度を上げるために、式インデックスを作成できます:

CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));

または、すべてをマテリアライズドビューに保存します。

ここから取られた例:http : //bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/


2
これは正解です。たとえば、Postgrestがこの動作を「計算列」と呼ぶ方法を参照してください。
フィアットヤフ

タイプミス、私は思う-選択は、select people.full_name from peopleまたはのはずselect full_name(people) from peopleですか?
バルガスト

いいえ、そのように動作します。「select people.full_name from people」のプレフィックスは、通常のSQLと同様に省略できます。
ファビアンゼインドル

私はあきらめたずっと後に、この答えを逃しました。提案をありがとう。
マンゴ

1
受け入れられた答えを変更できますか?
ファビアンZeindl

6

いいえ、これは現在(Postgres 9.6現在)サポートされていません。

唯一の回避策は、インデックスを作成する必要がない単純な計算である場合、トリガーまたはビューを使用することです。


ラット。パフォーマンスが必要な場合は、マテリアライズドビューに進むことができると思います。この機能は既にコンペティションで利用可能であるため、リクエストを追加しました。
マンゴ

1
MVIEWは必要ありません。トリガーのある列では、列のコンテンツにインデックスを付けることもできます
-a_horse_with_no_name

基本的に他のデータの繰り返しである追加の実列を格納するという哲学的な問題があります。テーブルを非正規化します。
マンゴ

5
計算列とは、正規化されていないデータを保存することです。計算列の値がどのように生成されるかは問題ではありません。「実際の」計算列とトリガーを介して生成される列との概念的な違いはありません
a_horse_with_no_name

別の回避策(場合によって)は、式にインデックスを付けることです。
ypercubeᵀᴹ

5

はい: GENERATED ALWAYS AS … STORED

Postgres 12は、SQL:2003標準で述べられているように、生成された列の機能を追加します。

値の時に発生するINSERT、またはUPDATE、その後、他の値のような行に記憶されます。

生成されるのは、同じテーブルのベース列または不変の関数に基づく必要があります。

構文は単純CREATE TABLEです。

GENERATED ALWAYS AS ( generation_expr ) STORED 

例:

CREATE TABLE people (
    ...,
    height_cm NUMERIC,
    height_in NUMERIC GENERATED ALWAYS AS ( height_cm / 2.54 ) STORED
);

特徴:

  • インデックスを作成できます。
  • SQL標準の一部。

警告:

  • 同じテーブルの列に基づく(関連するテーブルではない)
  • パーティション化は許可されていません(パーティションキーの一部にすることはできません)
  • データは常に行に書き込まれ、ストレージのスペースを取ります
    • 将来の機能では、ストレージなしでオンザフライで計算された値に対してVIRTUALが提供される可能性があります
  • 単一世代の詳細(別の生成列ではなく、ベース列を使用)
  • GENERATED BY DEFAULTはありません(値をオーバーライドできません)
  • BEFOREトリガーのgen-colにアクセスできません(値はまだ決定されていません)
  • 関数は不変でなければなりません

見る:


その情報をありがとう。バージョン12はまだ完全にはリリースされていないようですが、楽しみにしています。PostgreSQLはより標準的な構文を使用しますが、それ以外はMSSQLと同じです。私はここでSQL2003の仕様が見つかりました:sigmodrecord.org/publications/sigmodRecord/0403/...。私はいつも、SQLは非常に動きの遅い標準であり、DBMSの実装はさらに遅いと言ってきました。
マンゴ

0

ユースケースに応じて、新しい列を宣言し、挿入/更新のトリガーをその列に入力することで、この種の動作を実現できます。

可能であれば上記の回答を使用して、既に持っているものから派生する可能性のあるデータの重複を避けますが、それはトリックを行い、一度計算して保存したい計算集約的な派生フィールドに役立つ可能性があります。

このアプローチは、18桁のキーのうち15桁しか持っていない(最後の3桁は単なるチェックサムである)が、外部キー関係を強制できるようにしたいという問題に対処するために検討しました。

トリガーに関するPGドキュメント: https //www.postgresql.org/docs/9.6/sql-createtrigger.html

W3の例:https : //www.w3resource.com/PostgreSQL/postgresql-triggers.php

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.