生成列是一种特殊列,其值总是根据其他列计算得出。因此,对列而言,它就像视图对表一样。生成列有两种:存储型和虚拟型。存储型生成列在写入时(插入或更新时)计算,并像普通列一样占用存储空间。虚拟生成列不占用存储空间,而是在读取时计算。因此,虚拟生成列类似于视图,存储型生成列类似于物化视图(只是它总会自动更新)。 PostgreSQL 目前只实现了存储型生成列。
要创建生成列,可使用GENERATED ALWAYS AS子句,在CREATE TABLE中,例如:
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触发器中访问生成列是不允许的。
逻辑复制会跳过生成列。