pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
生成列是一种特殊列,其值总是根据其他列计算得出。因此,对列而言,它就像视图对表一样。生成列有两种:存储型和虚拟型。存储型生成列在写入时(插入或更新时)计算,并像普通列一样占用存储空间。虚拟生成列不占用存储空间,而是在读取时计算。因此,虚拟生成列类似于视图,存储型生成列类似于物化视图(只是它总会自动更新)。
要创建生成列,可在 CREATE TABLE 中使用 GENERATED ALWAYS AS 子句,例如:
CREATE TABLE people (
...,
height_cm numeric,
height_in numeric GENERATED ALWAYS AS (height_cm / 2.54)
);
生成列默认是虚拟型。使用关键字 VIRTUAL 或 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 要求父列和子列在生成状态上已经匹配,但不要求它们的生成表达式相同。
在多重继承的情况下,如果某个父列是生成列,则所有父列都必须是生成列。如果它们的生成表达式并不完全相同,则必须为子列显式指定所需的表达式。
生成列的使用还有以下注意事项。
生成列与其底层基础列分别维护访问权限。因此,可以安排成某个角色能够读取生成列,但不能读取底层基础列。
对于虚拟生成列,只有在生成表达式只使用防泄漏函数时,这种安排才完全安全(见 CREATE FUNCTION),但系统不会强制检查这一点。
生成表达式中所用函数的权限,会在表达式实际执行时分别在写入或读取时检查,就像生成表达式是由使用生成列的查询直接调用的一样。生成列的用户必须拥有调用生成表达式中所有函数的权限。生成表达式中的函数是以执行查询的用户的权限还是函数所有者的权限来执行,取决于这些函数被定义为 SECURITY INVOKER 还是 SECURITY DEFINER。
从概念上说,生成列会在 BEFORE 触发器运行之后更新。因此,BEFORE 触发器中对基础列所做的修改会反映到生成列中。反过来,在 BEFORE 触发器中访问生成列是不允许的。
生成列可以根据 CREATE PUBLICATION 参数 publish_generated_columns,或者通过把它们包含在 CREATE PUBLICATION 命令的列列表中,在逻辑复制期间被复制。目前这只支持存储型生成列。详情见第 29.6 节。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。英文原文本身的问题请通过上游文档表单反馈给 PostgreSQL 文档维护者。