web-dev-qa-db-ja.com

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

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

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

83

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 here

VIRTUALで生成された列は、次の反復で使用される場合があります。関連する:

それまでまで、属性表記を使用して、関数VIRTUAL生成列をエミュレートできます=(tbl.colは、仮想生成列のように見え、動作します。これは歴史的な理由でPostgresに存在するちょっとした構文の奇妙さであり、偶然にもケースに適合します。この関連する回答には、コード例があります

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

一致する expression index でサポートすることもできます-関数がIMMUTABLEである場合。好む:

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

代替案

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

「永続」(STORED)計算列は、機能的に同じ方法で triggers で実装できます。

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

102

はい、できます!!解決策は簡単、安全、そして高性能でなければなりません...

私はpostgresqlを初めて使用しますが、 expression index と組み合わせて view を使用して計算列を作成できるようです(ビューはオプションですが、少し簡単)。

私の計算が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);
_

これは explain で確認できます。

ただし、この時点では、列の作成方法を正確に知っているテーブルのユーザーに依存しています。作業を簡単にするために、元のテーブルの拡張バージョンに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_を使用できます。どのように動作するかを心配することなく、それらは良好なパフォーマンスを得るだけです。ビューは元のテーブルからデータをコピーしないため、パフォーマンス面でもメモリ面でも優れています。ただし、ビューへの更新/挿入はできず、ソーステーブルのみにできますが、本当に必要な場合は、 rules を使用してソーステーブルへの挿入と更新をリダイレクトできると思います私は自分で試したことがないので、その最後の点で間違っている)。

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

26
dan-man

これを行う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レコードの計算するフィールドを変更し、そのレコードを返します。

12
Elmer

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 demo

5
Lukasz Szozda

動作するコードを使用して計算された用語を使用していますが、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    ;
0
Wired604