PostgreSQLの計算/計算/仮想/派生列


113

PostgreSQLは、MS SQL Serverのように計算/計算された列をサポートしていますか?ドキュメントには何も見つかりませんが、この機能は他の多くのDBMSに含まれているため、何か不足している可能性があると思いました。

例:http : //msdn.microsoft.com/en-us/library/ms191250.aspx


ラテラルサブクエリ式(Postgres機能)を使用すると、各行に列を簡単に追加できます。
ビクター

回答:


139

SQL標準で定義され、DB2、MySQL、Oracleを含む一部のRDBMSで実装されているように、Postgres 11まで生成された列はサポートされていません。SQL Server の同様の「計算列」も同様です。

STORED生成されたカラムはPostgres 12で導入されました。簡単な例:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

ここに db <> fiddle

VIRTUAL生成された列には、次の反復の1つが含まれる場合があります。(まだPostgres 13にはありません)。

関連:


それまでは仮想生成列と同じように機能する属性表記()を使用VIRTUALする関数を使用して、生成列をエミュレートできます。これは、歴史的な理由でPostgresに存在する構文の奇妙な点であり、たまたまケースに当てはまります。この関連する回答にはコード例がありますtbl.col

SELECT * FROM tblただし、式(列のように見える)はに含まれていません。常に明示的にリストする必要があります。

関数が提供されている場合、一致する式のインデックスでサポートすることもできますIMMUTABLE。お気に入り:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

代替案

または、同様にVIEW、オプションで式インデックスと組み合わせて、同様の機能を実装できます。次にSELECT *、生成された列を含めることができます。

「持続」(STORED)計算列は、機能的に同じ方法でトリガーを使用して実装できます。

マテリアライズドビューは、Postgres 9.3以降実装された密接に関連する概念です。
以前のバージョンでは、MVを手動で管理できました。


一度にロードするデータの量に応じて、トリガーによって状況が大幅に遅くなる可能性があります。代わりに更新を検討したい場合があります。
sam yi

1
これらのソリューションは、OracleからPostgresに移行する場合、(テストケースのないコードベースへの大規模なコード変更なしでは)ほとんど役に立ちません。移行の観点からの解決策はありますか?
happybuddha 2016年

@happybuddha:質問として質問してください。コメントは場所ではありません。この質問へのリンクはいつでも可能です(ここにコメントを追加して、私の注意を得て、関連する質問にリンクしてください)。
Erwin Brandstetter 2016年

4
機能は現在開発中です:commitfest.postgresql.org/16/1443
r90t

1
@cryanbhu:セットアップと要件の詳細に依存します。必要な情報を記載した新しい質問をするかもしれません。
Erwin Brandstetter 2018

32

はい、できます! ソリューションは簡単、安全、そして高性能でなければなりません...

私はpostgresqlを使い始めたばかりですが、ビューと組み合わせて式インデックスを使用して計算列を作成できるようです(ビューはオプションですが、作業が少し楽になります)。

私の計算がmd5(some_string_field)であるとすると、次のようにインデックスを作成します。

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

これで、作用するクエリはすべてMD5(some_string_field)、最初から計算するのではなく、インデックスを使用します。例えば:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

これは説明で確認できます

ただし、この時点では、列の構築方法を正確に知っているテーブルのユーザーに依存しています。簡単にするためVIEWに、元のテーブルの拡張バージョンにを作成し、計算値を新しい列として追加できます。

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

これで、を使用some_table_augmentedするすべてのクエリはsome_string_field_md5、それがどのように機能するかを心配することなく使用できます。ビューは元のテーブルからデータをコピーしないため、パフォーマンスとメモリの両方で優れています。ただし、ソーステーブルにのみビューを更新または挿入することはできませんが、本当に必要な場合は、ルールを使用してソーステーブルに挿入と更新をリダイレクトできると思います(最後の点で間違っている可能性があります)自分で試したことがありません)。

編集:クエリに競合するインデックスが含まれる場合、プランナーエンジンが式インデックスをまったく使用しない場合があります。選択はデータに依存するようです。


1
説明または例を挙げていただけませんif the query involves competing indicesか?
dvtan 2017年

17

これを行う1つの方法は、トリガーを使用することです。

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

トリガーは、行が更新または挿入される前に発生します。NEWレコードを計算するフィールドを変更し、そのレコードを返します。


トリガーはいつ実際に発火しますか?私は上記を実行してこれを実行しましたinsert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;:戻り値は:1 2および4 8
happybuddha

2
insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;の値を試してみてくださいtwo自動的に計算されます!
Elmer、

8

PostgreSQL 12は生成された列をサポートします:

PostgreSQL 12 Beta 1がリリースされました!

生成された列

PostgreSQL 12では、他の列の内容を使用する式で値を計算する生成された列を作成できます。この機能は、挿入および更新時に計算され、ディスクに保存される、格納された生成列を提供します。クエリの一部として列が読み取られるときにのみ計算される仮想生成列は、まだ実装されていません。


生成された列

生成された列は、常に他の列から計算される特別な列です。したがって、ビューはテーブルと同じです。

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> fiddleデモ



1

まあ、これがあなたの言っていることかどうかはわかりませんが、Posgresは通常「ダミー」のETL構文をサポートしています。テーブルに空の列を1つ作成し、行の値に応じて計算されたレコードを入力する必要がありました。

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. それはとてもダミーなので、あなたが探しているものではないようです。
  2. 明らかにそれは動的ではなく、一度実行するだけです。しかし、それを引き金にするための障害はありません。

0

機能し、計算された用語を使用するコードがあります。PADBで実行する純粋なpostgresSQLではありません。

使い方はこちら

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;

PADBとは正確には何ですか?
ガーマン

ParAccel Analytic Database古くて素敵です... en.wikipedia.org/wiki/ParAccel
Wired604 '22

しかし、それはPostgresに関する質問とどのように関連していますか?もちろん、計算列をサポートするDBはたくさんあります。
ガーマン

時間をかけてコンテキストに戻らなくて申し訳ありませんでした... PADBはpostgressベースです!
Wired604

-6

チェック制約付きの軽量ソリューション:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
これは、計算列の概念とどのように関連していますか?説明してもよろしいですか?
Erwin Brandstetter 2013

4
同意、それは直接関係はありません。しかし、のような処理を行う必要がある場合の単純なケースの代わりになりますfield as 1 persisted
cinereo 2013

2
説明は確かにいいでしょう。この答えは、計算がdefault句で実行できる場合、デフォルトとチェック制約を使用して、誰もが値を変更できないようにすることができると思います。
ロスブラッドベリ

@Ross Bradbury:同意しますが、それは挿入に対してのみ機能します。従属列が更新された場合は機能しません。
Stefan Steiger
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.