生成列は常に他の列から計算される特別な列です。 ですから、これは列におけるテーブルに対するビューのようなものです。 生成列には格納と仮想の2種類があります。 格納生成列はそれが書かれた(挿入または更新)時に計算され、あたかも通常の列のようにストレージが割当てられます。 仮想列にはストレージは割り当てられず、列が読み出された時に計算されます。 つまり、仮想生成列はビューに似ており、格納生成列はマテリアライズドビューに似ています。(常に自動的に更新される点は除きます。) 今の所PostgreSQLは格納生成列のみを実装しています。
生成列を作るには、CREATE TABLE
でGENERATED ALWAYS AS
節を使ってください。例を示します。
CREATE TABLE people (
...,
height_cm numeric,
height_in numeric GENERATED ALWAYS AS (height_cm / 2.54) STORED
);
種類を格納生成列として選択するためにキーワードSTORED
を選択する必要があります。
より詳しくはCREATE TABLEをご覧ください。
生成列には直接書き込みができません。
INSERT
あるいはUPDATE
コマンドでは値を生成列には指定できませんが、キーワードDEFAULT
が指定できます。
デフォルトを備えた列と生成列の違いを考えてみましょう。
列のデフォルトは、他に値が指定されないときに、最初に行が挿入された時に一度だけ評価されます。
生成列は、行が変更された時に常に更新され、上書きはできません。
デフォルトを備えた列はテーブルの他の列を参照することはできませんが、生成式は通常それを行います。
デフォルトを備えた列は揮発性の関数、たとえばrandom()
や現在時刻を参照する関数を使用できますが、これは生成列では許されていません。
生成列の定義と生成列を伴うテーブルには以下の制限が適用されます。
生成式は不変関数のみが使用でき、副問合せ、あるいは現在の行以外へのいかなる参照も使用できません。
生成式はほかの生成列を参照できません。
生成式はtableoid
以外のシステム列を参照できません。
生成列は列デフォルトも識別定義も持てません。
生成列はパーティションキーの一部にはなれません。
外部テーブルは生成列を持つことができます。 詳細はCREATE FOREIGN TABLEをご覧ください。
継承の場合:
親列が生成列なら、子列もまた同じ式を用いた生成列でなければなりません。
子列の定義ではGENERATED
節は親列からコピーされるので、指定しないでください。
多重継承では、一つの親列が生成列なら、すべての親列は同じ式による生成列でなければなりません。
親列が生成列でなければ、子列は生成列として定義されるかもしれませんし、されないかもしれません。
生成列の利用の際には以下の追加の考慮が必要です。
生成列は元になる基底列とは別にアクセス権限を維持します。 ですから、ある特定のロールが生成列を読み出しつつも、元になる基底列からは読み出さないように調整することが可能です。
概念的には、生成列はBEFORE
トリガが走った後に更新されます。
ですから、BEFORE
トリガの中で基底列に加えられた変更は生成列に反映されます。
しかし逆に生成列をBEFORE
トリガの中でアクセスすることは許されません。