產生式欄位是一種特殊的欄位,它總是從其他欄位計算而來。因此,它對於欄位而言,就像視窗對於表格一樣。有兩種產生式欄位:儲存式和虛擬式。儲存式產生式欄位在寫入時(插入或更新時)進行計算,並像普通欄位一樣佔用儲存空間。虛擬式產生式欄位不佔用儲存空間,並在讀取時進行計算。因此,虛擬式產生式欄位類似於視窗,而儲存式產生式欄位類似於實體化視窗(除了它總是自動更新)。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。
對於繼承和分割
如果父欄位是產生式欄位,則其子欄位也必須是產生式欄位;但是,子欄位可以具有不同的產生式表示式。 在插入或更新列期間實際應用的產生式表示式是與列實際所在的表格相關聯的表示式。(這與欄位預設值的行為不同:對於這些預設值,應用於查詢中命名的表格相關聯的預設值。)
如果父欄位不是產生式欄位,則其子欄位也不能是產生式欄位。
對於繼承表格,如果您在 CREATE TABLE ... INHERITS
中編寫子欄位定義時沒有任何 GENERATED
子句,則其 GENERATED
子句將自動從父欄位複製。ALTER TABLE ... INHERIT
將堅持父欄位和子欄位在產生狀態方面已經匹配,但它不會要求它們的產生式表示式匹配。
類似地,對於分割表格,如果您在 CREATE TABLE ... PARTITION OF
中編寫子欄位定義時沒有任何 GENERATED
子句,則其 GENERATED
子句將自動從父欄位複製。ALTER TABLE ... ATTACH PARTITION
將堅持父欄位和子欄位在產生狀態方面已經匹配,但它不會要求它們的產生式表示式匹配。
在多重繼承的情況下,如果一個父欄位是產生式欄位,則所有父欄位都必須是產生式欄位。 如果它們並非都具有相同的產生式表示式,則必須明確指定子欄位的所需表示式。
以下額外注意事項適用於產生式欄位的使用。
產生式欄位維護與其底層基本欄位不同的存取權限。 因此,可以進行安排,以便特定的角色可以從產生式欄位讀取,但不能從底層基本欄位讀取。
從概念上講,產生式欄位會在 BEFORE
觸發器執行後更新。 因此,在 BEFORE
觸發器中對基本欄位所做的變更將反映在產生式欄位中。 但相反地,不允許在 BEFORE
觸發器中存取產生式欄位。
產生式欄位會跳過邏輯複製,並且不能在 CREATE PUBLICATION
欄位清單中指定。
如果您在文件中發現任何不正確、與特定功能的體驗不符或需要進一步澄清的地方,請使用此表單來報告文件問題。