ALTER TABLE
ALTER TABLE — 更改表的定义
摘要
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 [ CONCURRENTLY | FINALIZE ]
where action is one of:
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 | DEFAULT }
ALTER [ COLUMN ] column_name SET COMPRESSION compression_method
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 ACCESS METHOD new_access_method
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_ROLE | CURRENT_USER | SESSION_USER }
REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
and partition_bound_spec is:
IN ( partition_bound_expr [, ...] ) |
FROM ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] )
TO ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] ) |
WITH ( MODULUS numeric_literal, REMAINDER numeric_literal )
and column_constraint is:
[ 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 [ NULLS [ NOT ] DISTINCT ] 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 ]
and table_constraint is:
[ CONSTRAINT constraint_name ]
{ CHECK ( expression ) [ NO INHERIT ] |
UNIQUE [ NULLS [ NOT ] DISTINCT ] ( 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 ]
and table_constraint_using_index is:
[ CONSTRAINT constraint_name ]
{ UNIQUE | PRIMARY KEY } USING INDEX index_name
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
index_parameters in UNIQUE, PRIMARY KEY, and EXCLUDE constraints are:
[ INCLUDE ( column_name [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ USING INDEX TABLESPACE tablespace_name ]
exclude_element in an EXCLUDE constraint is:
{ column_name | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]
referential_action in a FOREIGN KEY/REFERENCES constraint is:
{ NO ACTION | RESTRICT | CASCADE | SET NULL [ ( column_name [, ... ] ) ] | SET DEFAULT [ ( column_name [, ... ] ) ] }
说明
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
子句。使用此表单时,列的统计信息将被移除,因此建议之后对表运行
ANALYZE
。SET
/DROP DEFAULT
#这些表单设置或移除一列的默认值(其中移除等同于将默认值设置为 NULL)。新的默认值仅适用于后续的
INSERT
或UPDATE
命令;它不会导致表中已有的行发生更改。SET
/DROP NOT NULL
#这些表单更改一列是否标记为允许空值或拒绝空值。
SET NOT NULL
只能应用于表中没有任何记录对该列包含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
一样,这些形式只会影响后续INSERT
和UPDATE
命令的行为;它们不会导致表中已有的行发生更改。如果指定了
DROP IDENTITY IF EXISTS
并且该列不是标识列,则不会引发错误。在这种情况下,会发出一个通知。SET
sequence_option
RESTART
#这些形式会更改现有标识列的底层序列。
sequence_option
是ALTER SEQUENCE
支持的一个选项,例如INCREMENT BY
。SET STATISTICS
#此形式为后续
ANALYZE
操作设置每列统计信息收集目标。目标可以设置在 0 到 10000 的范围内;或者,将其设置为 -1 以恢复使用系统默认统计信息目标 (default_statistics_target)。有关 PostgreSQL 查询计划程序使用统计信息的更多信息,请参阅 第 14.2 节。SET STATISTICS
会获取SHARE UPDATE EXCLUSIVE
锁。SET (
attribute_option
=value
[, ... ] )RESET (
#attribute_option
[, ... ] )此表单设置或重置每个属性选项。目前,唯一定义的每个属性选项是
n_distinct
和n_distinct_inherited
,它们覆盖后续ANALYZE
操作所做的不同值估计数。n_distinct
影响表本身的统计信息,而n_distinct_inherited
影响为表及其继承子项收集的统计信息。当设置为正值时,ANALYZE
将假定该列恰好包含指定数量的不同非空值。当设置为负值时(该值必须大于或等于 -1),ANALYZE
将假定该列中不同非空值的数目与表的规模成线性关系;确切计数通过将估计的表大小乘以给定数目的绝对值来计算。例如,-1 的值表示该列中的所有值都不同,而 -0.5 的值表示每个值平均出现两次。当表的大小随时间而变化时,这可能很有用,因为直到查询计划时间才执行按表中的行数相乘。指定 0 的值以恢复正常估计不同值的数目。有关 PostgreSQL 查询计划程序使用统计信息详情,请参阅 第 14.2 节。更改每个属性选项会获取
SHARE UPDATE EXCLUSIVE
锁。SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT }
#此表单设置列的存储模式。这控制该列是内联存储还是在辅助 表中存储,以及数据是否应压缩。对于固定长度值(如
integer
),必须使用PLAIN
,且为内联、未压缩。MAIN
用于内联、可压缩数据。EXTERNAL
用于外部、未压缩数据,而EXTENDED
用于外部、压缩数据。编写DEFAULT
将存储模式设置为列数据类型的默认模式。EXTENDED
是大多数支持非PLAIN
存储的数据类型的默认值。使用EXTERNAL
将使对非常大的text
和bytea
值的子字符串操作运行得更快,但代价是增加存储空间。请注意,ALTER TABLE ... SET STORAGE
本身不会更改表中的任何内容;它只是设置在将来的表更新期间要执行的策略。有关更多信息,请参见 第 73.2 节。SET COMPRESSION
#compression_method
此表单设置列的压缩方法,确定将来插入的值将如何压缩(如果存储模式允许压缩)。这不会导致表被重写,因此现有数据仍可能使用其他压缩方法进行压缩。如果使用 pg_restore 还原表,则所有值都将使用配置的压缩方法重写。但是,当从另一个关系中插入数据时(例如,通过
INSERT ... SELECT
),源表中的值不一定被解除 TOAST,因此任何先前压缩的数据都可能保留其现有的压缩方法,而不是使用目标列的压缩方法重新压缩。支持的压缩方法为pglz
和lz4
。(仅当在构建 PostgreSQL 时使用--with-lz4
时,lz4
才可用。)此外,compression_method
可以是default
,它会在插入数据时查询 default_toast_compression 设置来选择默认行为,以确定要使用的方法。ADD
#table_constraint
[ NOT VALID ]此表单使用与
CREATE TABLE
相同的约束语法向表中添加一个新约束,加上选项NOT VALID
,该选项目前只允许用于外键和 CHECK 约束。通常,此表单将导致扫描表以验证表中所有现有行是否满足新约束。但是,如果使用了
NOT VALID
选项,则会跳过此可能很长的扫描。约束仍将对后续插入或更新强制执行(即,如果没有匹配的行(对于外键)或新行不匹配指定的检查条件,则它们将失败)。但在使用VALIDATE CONSTRAINT
选项验证约束之前,数据库不会假定约束对表中的所有行都成立。有关使用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 KEY
或UNIQUE
约束。索引的所有列都将包含在约束中。索引不能有表达式列,也不能是部分索引。此外,它必须是具有默认排序顺序的 b 树索引。这些限制确保索引等同于通过常规
ADD PRIMARY KEY
或ADD UNIQUE
命令构建的索引。如果指定了
PRIMARY KEY
,并且索引的列尚未标记为NOT NULL
,那么此命令将尝试对每个此类列执行ALTER COLUMN SET NOT NULL
。这需要进行全表扫描以验证列不包含空值。在所有其他情况下,这是一个快速的操作。如果提供了约束名称,则索引将被重命名以匹配约束名称。否则,约束将与索引同名。
执行此命令后,该索引将由约束“拥有”,就像该索引是由常规
ADD PRIMARY KEY
或ADD UNIQUE
命令构建的一样。特别是,删除约束也会使索引消失。此形式目前不受分区表支持。
注意
在需要添加新约束但又不想长时间阻塞表更新的情况下,使用现有索引添加约束可能会有所帮助。要执行此操作,请使用
CREATE INDEX CONCURRENTLY
创建索引,然后使用此语法将其安装为正式约束。请参见下面的示例。ALTER CONSTRAINT
#此形式会更改之前创建的约束的属性。目前,只能更改外键约束。
VALIDATE CONSTRAINT
#此形式会验证之前创建为
NOT VALID
的外键或检查约束,方法是扫描表以确保没有不满足约束的行。如果约束已标记为有效,则不会发生任何情况。(有关此命令的用处的说明,请参见下面的 注释。)此命令会获取
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
,以便它也在副本上触发。当此命令应用于分区表时,除非指定了
ONLY
,否则也会更新分区中相应克隆触发器的状态。此命令获取
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 ACCESS METHOD
#此表单通过重写来更改表的访问方法。有关详细信息,请参阅 第 63 章。
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 }
#此表单将表从未记录更改为已记录或反之亦然(请参阅
UNLOGGED
)。它不能应用于临时表。这也将更改链接到表(用于标识或序列列)的任何序列的持久性。但是,也可以单独更改此类序列的持久性。
SET (
#storage_parameter
[=value
] [, ... ] )此表单更改表的存储参数。有关可用参数的详细信息,请参阅
CREATE TABLE
文档中的 存储参数。请注意,此命令不会立即修改表内容;根据参数,您可能需要重写表以获得所需的效果。可以使用VACUUM FULL
、CLUSTER
或强制表重写的ALTER TABLE
表单之一来完成此操作。对于计划程序相关参数,更改将在下次锁定表时生效,因此当前执行的查询不会受到影响。SHARE UPDATE EXCLUSIVE
锁将用于填充因子、toast 和自动清理存储参数,以及规划器参数parallel_workers
。RESET (
#storage_parameter
[, ... ] )此表单将一个或多个存储参数重置为其默认值。与
SET
一样,可能需要重写表以完全更新表。INHERIT
#parent_table
此表单将目标表添加为指定父表的新的子表。随后,对父表的查询将包括目标表的记录。要添加为子表,目标表必须已包含与父表完全相同的列(它也可以有其他列)。列必须具有匹配的数据类型,如果它们在父表中具有
NOT NULL
约束,则它们在子表中也必须具有NOT NULL
约束。还必须为父表的全部
CHECK
约束提供匹配的子表约束,但标记为不可继承的约束除外(即,在父表中使用ALTER TABLE ... ADD CONSTRAINT ... NO INHERIT
创建的约束),这些约束将被忽略;匹配的所有子表约束都不得标记为不可继承。当前不考虑UNIQUE
、PRIMARY KEY
和FOREIGN KEY
约束,但这可能会在将来发生变化。NO INHERIT
#parent_table
此表单将目标表从指定父表的子表列表中移除。对父表的查询将不再包括从目标表获取的记录。
OF
#type_name
此表单将表链接到复合类型,就像
CREATE TABLE OF
已经形成它一样。表的列名和类型列表必须与复合类型的列表完全匹配。表不得从任何其他表继承。这些限制确保CREATE TABLE OF
允许等效的表定义。NOT OF
#此表单将类型表与其类型分离。
OWNER TO
#此表单将表、序列、视图、物化视图或外部表的所有者更改为指定的用户。
REPLICA IDENTITY
#此表单更改写入预写日志的信息,以识别已更新或已删除的行。在大多数情况下,仅当旧值与新值不同时才会记录每个列的旧值;但是,如果旧值存储在外部,则无论是否更改,它始终会被记录。此选项仅在使用逻辑复制时才有效。
RENAME
#RENAME
表单更改表(或索引、序列、视图、物化视图或外部表)的名称、表中单个列的名称或表的约束的名称。在重命名具有基础索引的约束时,索引也会被重命名。对存储的数据没有影响。SET SCHEMA
#此表单将表移动到另一个模式中。关联的索引、约束和由表列拥有的序列也会被移动。
ATTACH PARTITION
#partition_name
{ FOR VALUESpartition_bound_spec
| DEFAULT }此表单将现有表(本身可能已分区)附加为目标表的某个分区。可以使用
FOR VALUES
将表附加为特定值的某个分区,或使用DEFAULT
将其附加为默认分区。对于目标表中的每个索引,将在附加表中创建一个对应的索引;或者,如果已存在等效索引,则会将其附加到目标表的索引,就像已执行ALTER INDEX ATTACH PARTITION
一样。请注意,如果现有表是外部表,则当前不允许将该表附加为目标表的分区,如果目标表上有UNIQUE
索引。(另请参阅 CREATE FOREIGN TABLE。)对于目标表中存在的每个用户定义的行级触发器,将在附加表中创建一个对应的触发器。使用
FOR VALUES
的分区使用与CREATE TABLE
中的partition_bound_spec
相同的语法。分区边界规范必须与目标表的分区策略和分区键对应。要附加的表必须具有与目标表完全相同且不多的所有列;此外,列类型也必须匹配。此外,它还必须具有目标表的所有NOT NULL
和CHECK
约束。当前不考虑FOREIGN KEY
约束。如果父表中不存在UNIQUE
和PRIMARY KEY
约束,则会在分区中创建这些约束。如果要附加的表的任何CHECK
约束标记为NO INHERIT
,则该命令将失败;必须在没有NO INHERIT
子句的情况下重新创建此类约束。如果新分区是常规表,则执行全表扫描以检查表中的现有行是否违反分区约束。可以通过在运行此命令之前向表添加允许仅满足所需分区约束的行有效的
CHECK
约束来避免此扫描。CHECK
约束将用于确定无需扫描表即可验证分区约束。但是,如果任何分区键都是表达式并且分区不接受NULL
值,则此方法不起作用。如果附加不接受NULL
值的列表分区,也请向分区键列添加NOT NULL
约束,除非它是表达式。如果新分区是外部表,则不执行任何操作来验证外部表中的所有行是否遵守分区约束。(请参阅 CREATE FOREIGN TABLE 中关于外部表约束的讨论。)
当表具有默认分区时,定义新分区将更改默认分区的约束。默认分区不能包含任何需要移动到新分区的行,并且将扫描默认分区以验证没有此类行。如果存在适当的
CHECK
约束,则可以避免此扫描,就像新分区的扫描一样。同样,当默认分区是外部表时,也会始终跳过新分区的扫描。附加分区除了在要附加的表和默认分区(如果有)上附加
ACCESS EXCLUSIVE
锁之外,还会在父表上获取SHARE UPDATE EXCLUSIVE
锁。如果要附加的表本身是分区表,则还必须对所有子分区保持其他锁。同样,如果默认分区本身是分区表。可以通过添加
CHECK
约束来避免对子分区的锁定,如 第 5.11.2.2 节 中所述。DETACH PARTITION
#partition_name
[ CONCURRENTLY | FINALIZE ]此形式分离目标表的指定分区。分离的分区继续作为独立表存在,但不再与分离其的分区有任何联系。附加到目标表索引的任何索引都将分离。从目标表中的索引克隆创建的任何触发器都将被移除。对引用此分区表的外键约束的任何表都将获取
SHARE
锁。如果指定
CONCURRENTLY
,它将使用降低的锁级别运行,以避免阻止可能正在访问分区表的其他会话。在此模式下,内部使用两个事务。在第一个事务期间,对父表和分区获取SHARE UPDATE EXCLUSIVE
锁,并将分区标记为正在分离;此时,提交事务并等待使用分区表的所有其他事务。一旦所有这些事务完成,第二个事务就会在分区表上获取SHARE UPDATE EXCLUSIVE
,在分区上获取ACCESS EXCLUSIVE
,并且分离过程完成。将与分区约束重复的CHECK
约束添加到分区。如果分区表包含默认分区,则CONCURRENTLY
不能在事务块中运行且不允许运行。如果指定
FINALIZE
,则完成先前被取消或中断的DETACH CONCURRENTLY
调用。分区表中一次最多可以有一个分区处于分离待定状态。
对单个表起作用的所有 ALTER TABLE 形式(RENAME
、SET SCHEMA
、ATTACH PARTITION
和DETACH PARTITION
除外)可以组合成一个要一起应用的多个更改的列表。例如,可以在单个命令中添加多个列和/或更改多个列的类型。对于大型表,这特别有用,因为只需要遍历一次表。
您必须拥有该表才能使用ALTER TABLE
。要更改表的架构或表空间,您还必须在新架构或表空间上具有CREATE
权限。要将表作为父表的新的子项添加,您还必须拥有父表。此外,要将表附加为该表的新的分区,您必须拥有要附加的表。要更改所有者,您必须能够将SET ROLE
设置为新的所有者角色,并且该角色必须对表的架构具有CREATE
权限。(这些限制强制要求更改所有者不会执行通过删除和重新创建表无法执行的任何操作。但是,超级用户无论如何都可以更改任何表的拥有权。)要添加列或更改列类型或使用OF
子句,您还必须对数据类型具有USAGE
权限。
参数
IF EXISTS
#如果表不存在,则不抛出错误。在这种情况下,会发出通知。
name
#要更改的现有表的名称(可选的架构限定)。如果在表名前指定了
ONLY
,则只更改该表。如果未指定ONLY
,则更改表及其所有后代表(如果存在)。另外,可以在表名后指定*
以明确指示包括后代表。column_name
#新列或现有列的名称。
new_column_name
#现有列的新名称。
new_name
#表的名称。
data_type
#新列的数据类型或现有列的新数据类型。
table_constraint
#表的表约束。
constraint_name
#新约束或现有约束的名称。
CASCADE
#自动删除依赖于已删除列或约束的对象(例如,引用该列的视图),以及反过来依赖于这些对象的全部对象(请参见第 5.14 节)。
RESTRICT
#如果存在任何依赖对象,则拒绝删除列或约束。这是默认行为。
trigger_name
#要禁用或启用的单个触发器的名称。
ALL
#禁用或启用属于该表的全部触发器。(如果任何触发器是内部生成的约束触发器(例如,用于实现外键约束或可延迟唯一性及排除约束的触发器),则需要超级用户权限。)
USER
#禁用或启用属于该表的全部触发器,但内部生成的约束触发器除外,例如,用于实现外键约束或可延迟唯一性及排除约束的触发器。
index_name
#现有索引的名称。
storage_parameter
#表存储参数的名称。
value
#表存储参数的新值。这可能是数字或单词,具体取决于参数。
parent_table
#要与此表关联或取消关联的父表。
new_owner
#表的新的所有者的用户名。
new_access_method
#表将转换到的访问方法的名称。
new_tablespace
#表将移动到的表空间的名称。
new_schema
#表将移动到的模式的名称。
partition_name
#作为新分区附加或从此表分离的表的名称。
partition_bound_spec
#新分区的分区边界规范。有关其语法的更多详细信息,请参阅 CREATE TABLE。
注释
关键字COLUMN
是噪音,可以省略。
当使用ADD COLUMN
添加列并指定非易失性DEFAULT
时,将在语句执行时评估默认值并将结果存储在表的元数据中。该值将用于所有现有行的列。如果没有指定DEFAULT
,则使用 NULL。在这两种情况下,都不需要重写表。
添加具有不稳定DEFAULT
的列或更改现有列的类型将需要重写整个表及其索引。作为一项例外,在更改现有列的类型时,如果USING
子句不更改列内容,并且旧类型可以二进制强制转换为新类型或在新的类型上不受约束的域,则不需要重写表。但是,索引必须始终重建,除非系统可以验证新索引在逻辑上等同于现有索引。例如,如果已更改列的排序规则,则始终需要重建索引,因为新的排序顺序可能不同。然而,在没有排序规则更改的情况下,可以将列从text
更改为varchar
(或反之亦然),而无需重建索引,因为这些数据类型以相同的方式排序。对于大表而言,表和/或索引重建可能需要大量时间;并且暂时需要多达两倍的磁盘空间。
添加CHECK
或NOT NULL
约束需要扫描表以验证现有行是否满足约束,但不需要重写表。
类似地,在附加新分区时,可以扫描它以验证现有行是否满足分区约束。
在单个ALTER TABLE
中提供指定多个更改的选项的主要原因是,多个表扫描或重写可以由此合并到表上的单个遍历中。
扫描大表以验证新的外键或检查约束可能需要很长时间,并且在ALTER TABLE ADD CONSTRAINT
命令提交之前,对表的其他更新将被锁定。NOT VALID
约束选项的主要目的是减少添加约束对并发更新的影响。使用NOT VALID
,ADD CONSTRAINT
命令不会扫描表,并且可以立即提交。之后,可以发出VALIDATE CONSTRAINT
命令以验证现有行是否满足约束。验证步骤不需要锁定并发更新,因为它知道其他事务将对它们插入或更新的行强制执行约束;只需要检查预先存在的行。因此,验证仅获取正在更改的表上的SHARE UPDATE EXCLUSIVE
锁。(如果约束是外键,则还需要在约束引用的表上获取ROW SHARE
锁。)除了提高并发性之外,在已知表包含预先存在的违规的情况下,使用NOT VALID
和VALIDATE CONSTRAINT
也很有用。一旦约束就位,就不能插入新的违规,并且可以在VALIDATE CONSTRAINT
最终成功之前从容地更正现有问题。
DROP COLUMN
表单不会物理删除列,而只是让 SQL 操作无法看到它。表中后续的插入和更新操作会为该列存储一个空值。因此,删除列很快,但不会立即减小表的磁盘大小,因为已删除列占用的空间不会被回收。随着现有行被更新,该空间会随着时间推移而被回收。
要强制立即回收已删除列占用的空间,您可以执行执行整个表重写的ALTER TABLE
的一种形式。这会导致使用空值替换已删除列来重建每一行。
ALTER TABLE
的重写形式不具备 MVCC 安全性。在表重写之后,如果并发事务使用在重写发生之前获取的快照,则该表将显示为空。有关更多详细信息,请参阅第 13.6 节。
SET DATA TYPE
的USING
选项实际上可以指定涉及行的旧值的任何表达式;也就是说,它可以引用其他列以及正在转换的列。这允许使用SET DATA TYPE
语法进行非常通用的转换。由于这种灵活性,USING
表达式不会应用于列的默认值(如果有);结果可能不是默认值所需的常量表达式。这意味着当没有从旧类型到新类型的隐式或赋值转换时,SET DATA TYPE
可能会无法转换默认值,即使提供了USING
子句。在这种情况中,请使用DROP DEFAULT
删除默认值,执行ALTER TYPE
,然后使用SET DEFAULT
添加一个合适的新的默认值。类似的注意事项适用于涉及该列的索引和约束。
如果一个表有任何后代表,则不允许在不向后代执行相同操作的情况下添加、重命名或更改父表中列的类型。这可确保后代始终具有与父代匹配的列。类似地,CHECK
约束不能在父代中重命名,而必须在所有后代中也重命名,以便CHECK
约束在父代及其后代之间也匹配。(不过,该限制不适用于基于索引的约束。)此外,由于从父代中选择也会从其后代中选择,因此父代上的约束不能标记为有效,除非它也标记为对这些后代有效。在所有这些情况下,ALTER TABLE ONLY
都将被拒绝。
递归DROP COLUMN
操作仅当后代未从任何其他父代继承该列且从未对该列进行过独立定义时,才会删除后代表的列。非递归DROP COLUMN
(即ALTER TABLE ONLY ... DROP COLUMN
)绝不会删除任何后代列,而是将它们标记为独立定义而不是继承。非递归DROP COLUMN
命令将对分区表失败,因为表的全部分区必须具有与分区根相同的列。
标识列的操作(ADD GENERATED
、SET
等、DROP IDENTITY
),以及操作CLUSTER
、OWNER
和TABLESPACE
绝不会递归到后代表;也就是说,它们始终表现得好像指定了ONLY
。影响触发器状态的操作会递归到分区表的各个分区(除非指定了ONLY
),但绝不会递归到传统继承后代。添加约束仅对未标记为NO INHERIT
的CHECK
约束进行递归。
不允许更改系统目录表的任何部分。
有关有效参数的进一步说明,请参阅CREATE TABLE。第 5 章进一步介绍了继承。
示例
为表添加一个varchar
类型的列
ALTER TABLE distributors ADD COLUMN address varchar(30);
这将导致表中所有现有行的新列都填充为 null 值。
添加具有非空默认值的列
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);
通过USING
子句将包含 Unix 时间戳的整数列更改为timestamp with time zone
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;
兼容性
形式ADD
(不带USING INDEX
)、DROP [COLUMN]
、DROP IDENTITY
、RESTART
、SET DEFAULT
、SET DATA TYPE
(不带USING
)、SET GENERATED
和SET*
sequence_option*
符合 SQL 标准。其他形式是PostgreSQL对 SQL 标准的扩展。此外,在单个ALTER TABLE
命令中指定多个操作的能力也是一项扩展。
ALTER TABLE DROP COLUMN
可用于删除表的唯一列,从而留下一个零列表。这是 SQL 的扩展,它不允许零列表。