生成列是一种特殊的列,它总是从其他列计算得出。因此,它对于列的作用就像视图对于表的作用。 生成列有两种类型:存储生成列和虚拟生成列。存储生成列在写入(插入或更新)时计算, 并占用存储空间,就像普通列一样。虚拟生成列不占用存储空间,在读取时计算。 因此,虚拟生成列类似于视图,而存储生成列类似于物化视图(不同的是它总是自动更新)。 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
的列列表中指定。