选择 打开 改范围 完整检索页
受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10
当前 PostgreSQL 版本不在支持生命周期内。
您可以参阅当前版本的对应页面,或其他在上面列出的活跃大版本。

ALTER TABLE

ALTER TABLE — 更改一个表的定义

Synopsis

ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
    action [, ... ]
ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
    RENAME [ COLUMN ] column_name TO new_column_name
ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
    RENAME CONSTRAINT constraint_name TO new_constraint_name
ALTER TABLE [ IF EXISTS ] name
    RENAME TO new_name
ALTER TABLE [ IF EXISTS ] name
    SET SCHEMA new_schema
ALTER TABLE ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ]
    SET TABLESPACE new_tablespace [ NOWAIT ]
ALTER TABLE [ IF EXISTS ] name
    ATTACH PARTITION partition_name { FOR VALUES partition_bound_spec | DEFAULT }
ALTER TABLE [ IF EXISTS ] name
    DETACH PARTITION partition_name

其中action为以下之一:

    ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
    DROP [ COLUMN ] [ IF EXISTS ] column_name [ RESTRICT | CASCADE ]
    ALTER [ COLUMN ] column_name [ SET DATA ] TYPE data_type [ COLLATE collation ] [ USING expression ]
    ALTER [ COLUMN ] column_name SET DEFAULT expression
    ALTER [ COLUMN ] column_name DROP DEFAULT
    ALTER [ COLUMN ] column_name { SET | DROP } NOT NULL
    ALTER [ COLUMN ] column_name DROP EXPRESSION [ IF EXISTS ]
    ALTER [ COLUMN ] column_name ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]
    ALTER [ COLUMN ] column_name { SET GENERATED { ALWAYS | BY DEFAULT } | SET sequence_option | RESTART [ [ WITH ] restart ] } [...]
    ALTER [ COLUMN ] column_name DROP IDENTITY [ IF EXISTS ]
    ALTER [ COLUMN ] column_name SET STATISTICS integer
    ALTER [ COLUMN ] column_name SET ( attribute_option = value [, ... ] )
    ALTER [ COLUMN ] column_name RESET ( attribute_option [, ... ] )
    ALTER [ COLUMN ] column_name SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
    ADD table_constraint [ NOT VALID ]
    ADD table_constraint_using_index
    ALTER CONSTRAINT constraint_name [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
    VALIDATE CONSTRAINT constraint_name
    DROP CONSTRAINT [ IF EXISTS ]  constraint_name [ RESTRICT | CASCADE ]
    DISABLE TRIGGER [ trigger_name | ALL | USER ]
    ENABLE TRIGGER [ trigger_name | ALL | USER ]
    ENABLE REPLICA TRIGGER trigger_name
    ENABLE ALWAYS TRIGGER trigger_name
    DISABLE RULE rewrite_rule_name
    ENABLE RULE rewrite_rule_name
    ENABLE REPLICA RULE rewrite_rule_name
    ENABLE ALWAYS RULE rewrite_rule_name
    DISABLE ROW LEVEL SECURITY
    ENABLE ROW LEVEL SECURITY
    FORCE ROW LEVEL SECURITY
    NO FORCE ROW LEVEL SECURITY
    CLUSTER ON index_name
    SET WITHOUT CLUSTER
    SET WITHOUT OIDS
    SET TABLESPACE new_tablespace
    SET { LOGGED | UNLOGGED }
    SET ( storage_parameter [= value] [, ... ] )
    RESET ( storage_parameter [, ... ] )
    INHERIT parent_table
    NO INHERIT parent_table
    OF type_name
    NOT OF
    OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
    REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }

partition_bound_spec为:

IN ( partition_bound_expr [, ...] ) |
FROM ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] )
  TO ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] ) |
WITH ( MODULUS numeric_literal, REMAINDER numeric_literal )

column_constraint为:

[ CONSTRAINT constraint_name ]
{ NOT NULL |
  NULL |
  CHECK ( expression ) [ NO INHERIT ] |
  DEFAULT default_expr |
  GENERATED ALWAYS AS ( generation_expr ) STORED |
  GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] |
  UNIQUE index_parameters |
  PRIMARY KEY index_parameters |
  REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
    [ ON DELETE referential_action ] [ ON UPDATE referential_action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

table_constraint为:

[ CONSTRAINT constraint_name ]
{ CHECK ( expression ) [ NO INHERIT ] |
  UNIQUE ( column_name [, ... ] ) index_parameters |
  PRIMARY KEY ( column_name [, ... ] ) index_parameters |
  EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] |
  FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
    [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

table_constraint_using_index为:

    [ CONSTRAINT constraint_name ]
    { UNIQUE | PRIMARY KEY } USING INDEX index_name
    [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

UNIQUEPRIMARY KEYEXCLUDE约束中的index_parameters为:

[ INCLUDE ( column_name [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ USING INDEX TABLESPACE tablespace_name ]

EXCLUDE约束中的exclude_element为:

{ column_name | ( expression ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]

描述

ALTER TABLE更改现有表的定义。下面介绍几种子形式。请注意,每种子形式所需的锁级别可能不同。除非明确说明,否则会获取一个ACCESS EXCLUSIVE锁。当给出多个子命令时,获取的锁将是任一子命令所需的最严格锁。

ADD COLUMN [ IF NOT EXISTS ]

该形式使用与CREATE TABLE相同的语法向表中添加新列。如果指定了IF NOT EXISTS,且同名列已经存在,则不会报错。

DROP COLUMN [ IF EXISTS ]

该形式从表中删除一列。涉及该列的索引和表约束也会自动删除。如果删除该列会使某个引用它的多元统计信息只剩下一列数据,那么该统计信息也会被移除。如果表外有任何对象依赖于该列,例如外键引用或视图,你就需要指定CASCADE。如果指定了IF EXISTS而该列不存在,则不会报错;此时会发出一条提示。

SET DATA TYPE

该形式更改表中某列的类型。涉及该列的索引和简单表约束会通过重新解析最初提供的表达式,自动转换为使用新列类型。可选的COLLATE子句为新列指定排序规则;如果省略,排序规则是新列类型的默认排序规则。可选的USING子句指定如何根据旧值计算新列值;如果省略,默认转换与从旧数据类型到新数据类型的赋值转换相同。如果旧类型到新类型之间不存在隐式转换或赋值转换,则必须提供USING子句。

SET/DROP DEFAULT

这些形式设置或移除列的默认值(其中移除等同于将默认值设为 NULL)。新的默认值只会应用于后续的INSERTUPDATE命令;它不会导致表中已有的行发生变化。

SET/DROP NOT NULL

这些形式更改列是否被标记为允许空值,或拒绝空值。

只有当表中的记录都不包含该列的NULL值时,才能对列应用SET NOT NULL。通常,ALTER TABLE会通过扫描整个表来检查这一点;但是,如果存在一个有效的CHECK约束(并且未在同一命令中删除),能够证明不存在NULL,则会跳过表扫描。

如果该表是分区,并且某列在父表中标记为NOT NULL,则不能对该列执行DROP NOT NULL。要从所有分区删除NOT NULL约束,请在父表上执行DROP NOT NULL。即使父表没有NOT NULL约束,仍然可以按需将此类约束添加到单个分区;也就是说,即使父表允许空值,子表也可以禁止空值,但反之则不行。

DROP EXPRESSION [ IF EXISTS ]

该形式将存储的生成列转换为普通基列。列中的现有数据会保留,但今后的更改将不再应用生成表达式。

如果指定DROP EXPRESSION IF EXISTS且该列不是存储的生成列,则不会抛出错误;在这种情况下会发出通知。

ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY
SET GENERATED { ALWAYS | BY DEFAULT }
DROP IDENTITY [ IF EXISTS ]

这些形式改变列是否为标识列,或者更改现有标识列的生成属性。详情见CREATE TABLE。与SET DEFAULT类似,这些形式只影响后续INSERTUPDATE命令的行为;它们不会导致表中已有的行发生变化。

如果指定了DROP IDENTITY IF EXISTS,而该列不是标识列,则不会报错;此时会发出一条提示。

SET sequence_option
RESTART

这些形式更改支撑现有标识列的序列。sequence_optionALTER SEQUENCE支持的选项,例如INCREMENT BY

SET STATISTICS

该形式为后续ANALYZE操作设置每列的统计信息收集目标。目标可以设置在 0 到 10000 范围内;也可以将其设置为 -1,以恢复使用系统默认的统计目标(default_statistics_target)。有关PostgreSQL查询规划器使用统计信息的更多信息,请参见Section 14.2

SET STATISTICS会获取一个SHARE UPDATE EXCLUSIVE锁。

SET ( attribute_option = value [, ... ] )
RESET ( attribute_option [, ... ] )

该形式设置或重置每个属性的选项。目前,唯一已定义的每个属性选项是n_distinctn_distinct_inherited,它们会覆盖后续ANALYZE操作对非重复值数量的估计。n_distinct影响表本身的统计信息,而n_distinct_inherited影响为该表及其继承子表收集的统计信息,以及为分区表收集的统计信息。当指定值为正数时,查询规划器将假定该列恰好包含指定数量的非空非重复值。也可以通过使用小于 0 且大于等于 -1 的值来指定小数值。这会指示查询规划器通过将指定数字的绝对值乘以表中估计行数来估算非重复值的数量。例如,值为 -1 表示该列中的所有值都不同,而值为 -0.5 表示每个值平均出现两次。当表的大小随时间变化时,这会很有用。有关PostgreSQL查询规划器如何使用统计信息的更多信息,请参见Section 14.2

更改每个属性的选项会获取一个SHARE UPDATE EXCLUSIVE锁。

SET STORAGE

该形式为列设置存储模式。这控制该列是内联保存还是保存在辅助TOAST表中,以及是否压缩数据。对于integer等定长值,必须使用PLAIN,数据以内联且未压缩的形式保存。MAIN用于内联的可压缩数据。EXTERNAL用于外部保存的未压缩数据,EXTENDED用于外部保存的压缩数据。对于支持非PLAIN存储的大多数数据类型,EXTENDED是默认值。使用EXTERNAL会使非常大的textbytea值上的子字符串操作运行得更快,但会增加存储空间。请注意,SET STORAGE本身不会更改表中的任何内容,它只会设置今后更新表时采用的策略。更多信息请参见Section 69.2

ADD table_constraint [ NOT VALID ]

该形式使用与CREATE TABLE相同的约束语法向表添加新约束,另外还提供NOT VALID选项;目前该选项只允许用于外键和 CHECK 约束。

通常,该形式会扫描表,以验证表中所有现有行都满足新约束。但如果使用了NOT VALID选项,就会跳过这一步可能非常耗时的扫描。该约束仍会对后续的插入或更新生效(也就是说,对于外键,除非被引用表中存在匹配行,否则操作会失败;对于检查约束,除非新行满足指定的检查条件,否则操作会失败)。但是,在通过VALIDATE CONSTRAINT选项完成验证之前,数据库不会假定该约束对表中的所有行都成立。请参见下面的Notes,了解使用NOT VALID选项的更多信息。

尽管大多数形式的ADD table_constraint需要ACCESS EXCLUSIVE锁,ADD FOREIGN KEY只需要SHARE ROW EXCLUSIVE锁。请注意,ADD FOREIGN KEY除了在声明约束的表上获取锁之外,还会在被引用的表上获取SHARE ROW EXCLUSIVE锁。

向分区表添加唯一约束或主键约束时还会有其他限制;请参见CREATE TABLE。此外,目前不能将分区表上的外键约束声明为NOT VALID

ADD table_constraint_using_index

该形式根据现有唯一索引向表添加新的PRIMARY KEYUNIQUE约束。索引的所有列都会包含在约束中。

索引不能包含表达式列,也不能是部分索引。此外,它必须是使用默认排序方式的 B-树 索引。这些限制确保该索引等效于使用常规ADD PRIMARY KEYADD UNIQUE命令构建的索引。

如果指定了PRIMARY KEY,且索引的列尚未标记为NOT NULL,则此命令会尝试对每个此类列执行ALTER COLUMN SET NOT NULL。这需要完整扫描表,以验证这些列不包含空值。在其他所有情况下,这都是快速操作。

如果提供了约束名称,索引将被重命名以匹配约束名称。否则,约束将与索引同名。

执行此命令后,索引将由约束拥有,其方式与常规ADD PRIMARY KEYADD UNIQUE命令构建索引时相同。特别是,删除约束也会使索引消失。

该形式目前不支持分区表。

Note

在需要添加新约束且不希望长时间阻塞表更新的情况下,使用现有索引添加约束可能很有用。为此,请使用CREATE INDEX CONCURRENTLY创建索引,然后使用此语法将其安装为正式约束。请参见下面的示例。

ALTER CONSTRAINT

该形式更改先前创建的约束的属性。目前只能更改外键约束。

VALIDATE CONSTRAINT

该形式通过扫描表来验证先前以NOT VALID创建的外键或 CHECK 约束,确保不存在不满足约束的行。如果约束已经标记为有效,则不执行任何操作。(有关此命令用途的说明,请参见下文Notes。)

此命令获取一个SHARE UPDATE EXCLUSIVE锁。

DROP CONSTRAINT [ IF EXISTS ]

该形式从表中删除指定的约束,以及约束底层的任何索引。如果指定IF EXISTS且约束不存在,则不会抛出错误;在这种情况下会发出通知。

DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER

这些形式配置属于表的触发器的触发。已禁用的触发器仍为系统所知,但在触发事件发生时不会执行。对于延迟触发器,会在事件发生时检查启用状态,而不是在实际执行触发器函数时检查。可以按名称指定单个触发器,或指定表上的所有触发器,或仅指定用户触发器,从而禁用或启用触发器(最后一种选项不包括内部生成的约束触发器,例如用于实现外键约束或可延迟唯一性约束和排他约束的触发器)。禁用或启用内部生成的约束触发器需要超级用户权限;应谨慎操作,因为如果不执行触发器,当然无法保证约束的完整性。

触发器触发机制还会受到配置变量session_replication_role的影响。简单启用的触发器(默认设置)会在复制角色为origin(默认值)或local时触发。配置为ENABLE REPLICA的触发器只会在会话处于replica模式时触发,配置为ENABLE ALWAYS的触发器则无论当前复制角色为何都会触发。

在默认配置下,这种机制的效果是触发器不会在副本上触发。这很有用,因为如果在源端使用触发器在表之间传播数据,那么复制系统也会复制传播的数据;触发器不应在副本上再次触发,否则会导致重复。但是,如果触发器用于其他目的(例如创建外部告警),则可以将其设置为ENABLE ALWAYS,使其也在副本上触发。

此命令获取一个SHARE ROW EXCLUSIVE锁。

DISABLE/ENABLE [ REPLICA | ALWAYS ] RULE

这些形式配置属于表的重写规则的触发。已禁用的规则仍为系统所知,但在查询重写期间不会应用。其语义与禁用或启用触发器时相同。对于ON SELECT规则会忽略此配置;为了使视图即使在当前会话处于非默认复制角色时也能正常工作,这类规则始终会被应用。

规则触发机制还会受到配置变量session_replication_role的影响,其方式与上文所述的触发器类似。

DISABLE/ENABLE ROW LEVEL SECURITY

这些形式控制表所属行安全策略的应用。如果启用且表不存在任何策略,则应用默认拒绝策略。请注意,即使禁用了表的行级安全性,表仍然可以存在策略。在这种情况下,这些策略将会被应用,并且会被忽略。另请参见CREATE POLICY

NO FORCE/FORCE ROW LEVEL SECURITY

这些形式控制当用户是表所有者时表所属行安全策略的应用。如果启用,当用户是表所有者时会应用行级安全策略。如果禁用(默认设置),当用户是表所有者时不会应用行级安全性。另请参见CREATE POLICY

CLUSTER ON

该形式为将来的CLUSTER操作选择默认索引。它实际上不会对表重新聚簇。

更改聚簇选项会获取一个SHARE UPDATE EXCLUSIVE锁。

SET WITHOUT CLUSTER

该形式从表中移除最近使用的CLUSTER索引规范。这会影响将来的聚簇操作(这些操作未指定索引)。

更改聚簇选项会获取一个SHARE UPDATE EXCLUSIVE锁。

SET WITHOUT OIDS

用于移除oid系统列的向后兼容语法。由于不再能够添加oid系统列,此语法不会产生任何效果。

SET TABLESPACE

该形式把表的表空间更改为指定的表空间,并将与该表关联的数据文件移动到新的表空间。表上的索引(如果有)不会被移动,但可以通过额外的SET TABLESPACE命令单独移动。当应用于分区表时,不会移动任何内容,但之后通过CREATE TABLE PARTITION OF创建的分区会使用该表空间,除非被TABLESPACE子句覆盖。

使用ALL IN TABLESPACE形式可以移动当前数据库中位于某个表空间中的所有表;该形式会先锁定所有待移动表,然后逐个移动。该形式还支持OWNED BY,从而只移动指定角色拥有的表。如果指定了NOWAIT,则一旦无法立即获取所需的全部锁,命令就会失败。请注意,系统目录不会通过此命令移动;如果需要,可改用ALTER DATABASE或显式的ALTER TABLE调用。information_schema中的关系不被视为系统目录的一部分,因此会被移动。另请参阅CREATE TABLESPACE

SET { LOGGED | UNLOGGED }

该形式将表从不记录 WAL 的表更改为记录 WAL 的表,或反之(参见UNLOGGED)。不能将其应用于临时表。

SET ( storage_parameter [= value] [, ... ] )

该形式更改表的一个或多个存储参数。有关可用参数的详情,请参见Storage Parameters,该参数在CREATE TABLE文档中有说明。请注意,该命令不会立即修改表内容;根据参数的不同,可能需要重写表才能达到预期效果。可以使用VACUUM FULLCLUSTER,或ALTER TABLE中会强制重写表的某种形式来完成重写。对于与规划器相关的参数,更改会从下次锁定表时生效,因此不会影响当前正在执行的查询。

对于 fillfactor、toast 和 autovacuum 存储参数,以及规划器参数parallel_workers,会获取SHARE UPDATE EXCLUSIVE锁。

RESET ( storage_parameter [, ... ] )

该形式把一个或多个存储参数重置为默认值。与SET一样,可能仍需要进行表重写才能让整张表完全更新。

INHERIT parent_table

该形式将目标表添加为指定父表的新子表。之后,对父表执行的查询将包含目标表的记录。要作为子表添加,目标表必须已经包含与父表相同的所有列(也可以有额外的列)。列必须具有匹配的数据类型;如果父表中的列具有NOT NULL约束,则子表中的相应列也必须具有NOT NULL约束。

父表的所有CHECK约束还必须在子表中有匹配的约束,但标记为不可继承的约束除外(即在父表中使用ALTER TABLE ... ADD CONSTRAINT ... NO INHERIT创建的约束);这类约束会被忽略。所有匹配的子表约束都不能标记为不可继承。目前不考虑UNIQUEPRIMARY KEYFOREIGN KEY约束,但将来可能会改变。

NO INHERIT parent_table

该形式把目标表从指定父表的子表列表中移除。对父表的查询将不再包含来自目标表的记录。

OF type_name

该形式把表关联到一个复合类型,就好像它是通过CREATE TABLE OF创建的一样。表的列名和类型列表必须与该复合类型完全一致。该表还必须不继承自任何其他表。这些限制保证了CREATE TABLE OF会允许一个等价的表定义。

NOT OF

该形式会解除类型化表与其类型之间的关联。

OWNER TO

该形式把表、序列、视图、物化视图或外部表的所有者更改为指定用户。

REPLICA IDENTITY #

该形式更改写入预写式日志以标识被更新或删除行的信息。在大多数情况下,只有当列的旧值不同于新值时,才会记录该旧值;但是,如果旧值存储在外部,则无论它是否发生变化,都会始终记录。除非正在使用逻辑复制,否则此选项没有效果。

DEFAULT

记录主键列(如果有)的旧值。这是非系统表的默认设置。

USING INDEX index_name

记录由指定索引覆盖的列的旧值。该索引必须是唯一的、非部分的、不可延迟的,并且只包含被标记为NOT NULL的列。如果该索引被删除,其行为与NOTHING相同。

FULL

记录该行中所有列的旧值。

NOTHING

不记录关于旧行的任何信息。这是系统表的默认值。

RENAME

RENAME形式用于更改表(或索引、序列、视图、物化视图或外部表)的名称、表中某个列的名称,或者表上某个约束的名称。重命名一个带有底层索引的约束时,该索引也会一并重命名。已存储的数据不会受到影响。

SET SCHEMA

该形式把表移动到另一个模式。相关索引、约束以及由表列拥有的序列也会一并移动。

ATTACH PARTITION partition_name { FOR VALUES partition_bound_spec | DEFAULT } #

该形式将现有表(该表本身也可以分区)附加为目标表的分区。可以使用FOR VALUES将表作为特定值的分区附加,也可以使用DEFAULT将其作为默认分区附加。对于目标表中的每个索引,附加表都会创建对应的索引;或者,如果已经存在等效索引,则会将其附加到目标表的索引上,就像执行了ALTER INDEX ATTACH PARTITION一样。请注意,如果现有表是外部表,而目标表上有UNIQUE索引,目前不允许将该表作为目标表的分区附加。(另请参见CREATE FOREIGN TABLE。)对于目标表中存在的每个用户定义行级触发器,都会在附加表中创建相应的触发器。

使用FOR VALUES的分区,其partition_bound_spec语法与CREATE TABLE中的相同。分区边界说明必须与目标表的分区策略和分区键相对应。待附加的表必须拥有与目标表完全相同且不多不少的列;此外,列类型也必须匹配。它还必须具有目标表上所有未标记为NO INHERITNOT NULLCHECK约束。目前不会考虑FOREIGN KEY约束。如果父表中的UNIQUEPRIMARY KEY约束尚不存在于该分区中,则会在该分区上创建这些约束。

如果新分区是普通表,则会执行一次全表扫描,以检查表中现有行不会违反分区约束。可以在执行此命令之前,先向该表添加一个有效的CHECK约束,使其只允许满足所需分区约束的行,从而避免这次扫描。系统会利用该CHECK约束来判断无须扫描该表以验证分区约束。不过,如果分区键中有任何一个是表达式,而该分区又不接受NULL值,则这一方法无效。如果附加的是一个不接受NULL值的列表分区,还应向分区键列添加NOT NULL约束,除非该分区键是表达式。

如果新分区是外部表,则不会执行任何检查来验证该外部表中的所有行都满足分区约束。(关于外部表上的约束,请参见CREATE FOREIGN TABLE中的讨论。)

当某个表具有默认分区时,定义一个新分区会改变默认分区的分区约束。默认分区不能包含任何本应移动到新分区中的行,因此系统会扫描默认分区以确认不存在此类行。和扫描新分区一样,如果存在适当的CHECK约束,也可以避免这次扫描;同样地,当默认分区是外部表时,这次扫描总会被跳过。

附加分区会在父表上获取一个SHARE UPDATE EXCLUSIVE锁,此外还会在被附加的表以及默认分区(如果有)上获取ACCESS EXCLUSIVE锁。

如果被附加的表本身是分区表,则还必须在其所有子分区上持有进一步的锁;如果默认分区本身也是分区表,也是如此。添加CHECK约束(如Section 5.11.2.2所述)可以避免对子分区加锁。

DETACH PARTITION partition_name

该形式会把目标表的指定分区分离出来。被分离的分区会继续作为一张独立表存在,但不再与原先所在的表保持任何关联。任何附加到目标表索引上的索引都会被分离。任何作为目标表中触发器克隆而创建的触发器都会被移除。对于任何在外键约束中引用该父分区表的表,都会获取SHARE锁。

对单个表执行操作的 ALTER TABLE 所有形式,除了RENAMESET SCHEMAATTACH PARTITIONDETACH PARTITION,都可以组合成一个列表,一起应用多项更改。例如,可以在一条命令中添加多列和/或更改多列的类型。这对大表尤其有用,因为只需对表执行一次遍历。

要使用ALTER TABLE,必须拥有该表。要更改表的模式或表空间,还必须在新模式或表空间上拥有CREATE权限。要将表作为父表的新子表添加,还必须拥有父表。要将表作为表的新分区附加,还必须拥有要附加的表。要更改所有者,还必须是新所有者角色的直接或间接成员,并且该角色必须在表所在模式上拥有CREATE权限。(这些限制确保更改所有者不会执行任何无法通过删除并重新创建表完成的操作。不过,超级用户无论如何都可以更改任何表的所有权。)要添加列、更改列类型或使用OF子句,还必须在数据类型上拥有USAGE权限。

参数

IF EXISTS

如果表不存在,则不抛出错误;在这种情况下会发出通知。

name

要更改的现有表的名称(可带模式限定)。如果在表名之前指定ONLY,则只更改该表。如果未指定ONLY,则更改该表及其所有后代表(如果有)。也可以在表名后指定*,以明确表示包含后代表。

column_name

新列或现有列的名称。

new_column_name

现有列的新名称。

new_name

表的新名称。

data_type

新列的数据类型,或现有列的新数据类型。

table_constraint

表的新约束。

constraint_name

新约束或现有约束的名称。

CASCADE

自动删除依赖于被删除列或约束的对象(例如引用该列的视图),并依次删除所有依赖于这些对象的对象(参见Section 5.14)。

RESTRICT

如果存在任何依赖对象,则拒绝删除列或约束。这是默认行为。

trigger_name

要禁用或启用的单个触发器的名称。

ALL

禁用或启用属于表的所有触发器。(如果触发器中有内部生成的约束触发器,例如用于实现外键约束或可延迟唯一性约束和排他约束的触发器,则需要超级用户权限。)

USER

禁用或启用属于表的所有触发器,但内部生成的约束触发器除外,例如用于实现外键约束或可延迟唯一性约束和排他约束的触发器。

index_name

现有索引的名称。

storage_parameter

表存储参数的名称。

value

表存储参数的新值。根据参数的不同,这可以是数字或单词。

parent_table

要与该表关联或解除关联的父表。

new_owner

表的新所有者的用户名。

new_tablespace

表将被移动到的表空间名称。

new_schema

表将被移动到的模式名称。

partition_name

要作为新分区附加或从该表分离的表的名称。

partition_bound_spec

新分区的分区边界规范。有关其语法的详情,请参见CREATE TABLE

注解

关键字COLUMN只是噪声,可以省略。

使用ADD COLUMN添加列且指定了非易失性的DEFAULT时,会在语句执行时计算默认值,并将结果存储在表的元数据中。对于所有现有行,该值都将用于该列。如果未指定DEFAULT,则使用 NULL。在这两种情况下都不需要重写表。

使用易失性的DEFAULT添加列,或更改现有列的类型,都需要重写整个表及其索引。作为更改现有列类型时的例外,如果USING子句不改变列内容,并且旧类型要么可以二进制强制转换为新类型,要么是新类型之上的无约束域,则不需要重写表;但受影响列上的任何索引仍必须重建。对于大型表,重建表和/或索引可能需要相当长的时间,并且会暂时需要最多两倍的磁盘空间。

添加CHECKNOT NULL约束需要扫描表,以验证现有行满足约束,但不需要重写表。

对于大表,表和/或索引重建可能会耗费大量时间,并且临时需要多达两倍的磁盘空间。

允许在单条ALTER TABLE命令中指定多项更改,主要是因为这样可以将多次表扫描或重写合并为一次遍历。

扫描大表以验证新的外键、检查或非空约束可能需要很长时间,并且在ALTER TABLE ADD CONSTRAINT命令提交之前,会阻止对该表的其他更新。NOT VALID约束选项的主要目的,是减小添加约束对并发更新的影响。使用NOT VALID时,ADD CONSTRAINT命令不会扫描表,因此可以立即提交。之后可以发出VALIDATE CONSTRAINT命令,以验证现有行满足该约束。验证步骤不需要阻止并发更新,因为它知道其他事务会对它们插入或更新的行强制执行该约束;只需检查预先存在的行。因此,验证只会在被修改的表上获取SHARE UPDATE EXCLUSIVE锁。(如果约束是外键,则被该约束引用的表上还需要ROW SHARE锁。)除了改善并发性之外,在已知该表包含既有违规数据的情况下,NOT VALIDVALIDATE CONSTRAINT也很有用。一旦约束已经建立,就不能再插入新的违规数据,而现有问题则可以从容修正,直到VALIDATE CONSTRAINT最终成功。

DROP COLUMN形式不会在物理上移除该列,而只是让它对 SQL 操作不可见。此后,对该表的插入和更新操作会为该列存储一个空值。因此,删除一列虽然很快,但不会立刻减少表占用的磁盘空间,因为被删除列所占用的空间尚未被回收。随着现有行被更新,这些空间会逐渐被回收。

若要强制立即回收已删除列所占的空间,可以执行任何一种会导致整表重写的ALTER TABLE形式。这样会重新构造每一行,并用空值替换被删除的列。

会重写表的ALTER TABLE形式对于 MVCC 来说并不安全。表重写完成后,如果并发事务使用的是在重写发生之前取得的快照,那么该表在这些并发事务看来会像一张空表。详见Section 13.5

SET DATA TYPEUSING选项实际上可以指定任何涉及该行旧值的表达式;也就是说,它既可以引用正在转换的列,也可以引用其他列。这使得使用SET DATA TYPE语法完成非常通用的转换成为可能。正因为这种灵活性,USING表达式不会应用到列的默认值(如果有)上,因为其结果可能不是默认值所要求的常量表达式。这意味着,当从旧类型到新类型不存在隐式或赋值类型转换时,即便提供了USING子句,SET DATA TYPE也可能仍然无法转换默认值。在这种情况下,可以先用DROP DEFAULT删除默认值,执行ALTER TYPE,然后再用SET DEFAULT添加一个合适的新默认值。类似的考虑也适用于涉及该列的索引和约束。

如果某个表有任何后代表,那么在不对后代表执行相同操作的情况下,就不允许在父表中添加列、重命名列或更改列类型。这保证了后代表始终拥有与父表相匹配的列。类似地,如果不同时重命名所有后代上的CHECK约束,就不能只在父表上重命名该检查约束,这样CHECK约束才能在父表及其后代之间保持匹配。(不过,这一限制不适用于基于索引的约束。)此外,由于查询父表时也会同时查询其后代,父表上的约束除非在这些后代上也被标记为有效,否则就不能被标记为有效。在所有这些情况下,ALTER TABLE ONLY都会被拒绝。

只有当某个后代表中的列既不是从其他父表继承而来,也从未有过该列的独立定义时,递归的DROP COLUMN操作才会移除该后代表中的此列。非递归的DROP COLUMN(即ALTER TABLE ONLY ... DROP COLUMN)永远不会移除任何后代列,而只会把它们标记为独立定义,而非继承得到。对于分区表,非递归的DROP COLUMN命令会失败,因为一张表的所有分区都必须与分区根表拥有相同的列。

标识列的操作(ADD GENERATEDSET等,以及DROP IDENTITY),以及TRIGGERCLUSTEROWNERTABLESPACE操作,都不会递归到后代表;也就是说,它们的行为始终如同指定了ONLY。添加约束时,只有未标记为NO INHERITCHECK约束会递归。

不允许更改系统目录表的任何部分。

有关有效参数的进一步说明,请参见CREATE TABLEChapter 5中还有关于继承的更多信息。

示例

要添加类型为varchar的列到表中:

ALTER TABLE distributors ADD COLUMN address varchar(30);

这会使表中所有现有行的新列都填入空值。

要添加一个带非空默认值的列:

ALTER TABLE measurements
  ADD COLUMN mtime timestamp with time zone DEFAULT now();

现有行会以当前时间作为新列的值填充,之后新行会接收其插入时的时间。

要添加一列,并先用与之后默认值不同的值填充它:

ALTER TABLE transactions
  ADD COLUMN status varchar(30) DEFAULT 'old',
  ALTER COLUMN status SET default 'current';

现有行会填入old,而后续命令的默认值将是current。 其效果与在两条单独的ALTER TABLE命令中发出这两个子命令相同。

要从表中删除一列:

ALTER TABLE distributors DROP COLUMN address RESTRICT;

要在一个操作中更改两个现有列的类型:

ALTER TABLE distributors
    ALTER COLUMN address TYPE varchar(80),
    ALTER COLUMN name TYPE varchar(100);

要把一个包含 Unix 时间戳的整数列改为 timestamp with time zone,并通过USING子句完成转换:

ALTER TABLE foo
    ALTER COLUMN foo_timestamp SET DATA TYPE timestamp with time zone
    USING
        timestamp with time zone 'epoch' + foo_timestamp * interval '1 second';

如果该列带有一个不能自动转换为新数据类型的默认值表达式,也是同样的做法:

ALTER TABLE foo
    ALTER COLUMN foo_timestamp DROP DEFAULT,
    ALTER COLUMN foo_timestamp TYPE timestamp with time zone
    USING
        timestamp with time zone 'epoch' + foo_timestamp * interval '1 second',
    ALTER COLUMN foo_timestamp SET DEFAULT now();

要重命名一个现有列:

ALTER TABLE distributors RENAME COLUMN address TO city;

重命名一个现有的表:

ALTER TABLE distributors RENAME TO suppliers;

重命名一个现有的约束:

ALTER TABLE distributors RENAME CONSTRAINT zipchk TO zip_check;

为一列增加一个非空约束:

ALTER TABLE distributors ALTER COLUMN street SET NOT NULL;

从一列移除一个非空约束:

ALTER TABLE distributors ALTER COLUMN street DROP NOT NULL;

要向一个表及其所有后代添加一个检查约束:

ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);

要只向一个表本身添加检查约束,而不添加到其后代:

ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5) NO INHERIT;

(该检查约束也不会被未来的后代表继承。)

要从一个表及其所有后代移除一个检查约束:

ALTER TABLE distributors DROP CONSTRAINT zipchk;

只从一个表移除一个检查约束:

ALTER TABLE ONLY distributors DROP CONSTRAINT zipchk;

(该检查约束在所有子表上仍然保留。)

为一个表增加一个外键约束:

ALTER TABLE distributors ADD CONSTRAINT distfk FOREIGN KEY (address) REFERENCES addresses (address);

为一个表增加一个外键约束,并且尽量不要影响其他工作:

ALTER TABLE distributors ADD CONSTRAINT distfk FOREIGN KEY (address) REFERENCES addresses (address) NOT VALID;
ALTER TABLE distributors VALIDATE CONSTRAINT distfk;

为一个表增加一个(多列)唯一约束:

ALTER TABLE distributors ADD CONSTRAINT dist_id_zipcode_key UNIQUE (dist_id, zipcode);

为一个表增加一个自动命名的主键约束,注意一个表只能拥有一个主键:

ALTER TABLE distributors ADD PRIMARY KEY (dist_id);

把一个表移动到一个不同的表空间:

ALTER TABLE distributors SET TABLESPACE fasttablespace;

把一个表移动到一个不同的模式:

ALTER TABLE myschema.distributors SET SCHEMA yourschema;

重建一个主键约束,并且在重建索引期间不阻塞更新:

CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx ON distributors (dist_id);
ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
    ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;

要把一个分区附加到范围分区表上:

ALTER TABLE measurement
    ATTACH PARTITION measurement_y2016m07 FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');

要把一个分区附加到列表分区表上:

ALTER TABLE cities
    ATTACH PARTITION cities_ab FOR VALUES IN ('a', 'b');

要把一个分区附加到哈希分区表上:

ALTER TABLE orders
    ATTACH PARTITION orders_p4 FOR VALUES WITH (MODULUS 4, REMAINDER 3);

要把默认分区附加到分区表上:

ALTER TABLE cities
    ATTACH PARTITION cities_partdef DEFAULT;

从一个分区表分离一个分区:

ALTER TABLE measurement
    DETACH PARTITION measurement_y2015m12;

兼容性

以下形式符合 SQL 标准:ADD(不带USING INDEX)、DROP [COLUMN]DROP IDENTITYRESTARTSET DEFAULTSET DATA TYPE(不带USING)、SET GENERATED以及SET sequence_option。其他形式是PostgreSQL对 SQL 标准的扩展。此外,在单条ALTER TABLE命令中指定多个操作的能力也是一种扩展。

ALTER TABLE DROP COLUMN可以被用来删除一个表的唯一的 列,从而留下一个零列的表。这是一种 SQL 的扩展,SQL 中不允许零列的表。

另见

CREATE TABLE