支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12

5.4. 生成列 #

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

不能直接写入生成列。在 INSERTUPDATE 命令中,不能为生成列指定值,但可以指定关键字 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 列列表中指定它们。

提交更正

如果您在文档中发现任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单报告文档问题。