ALTER TABLE — 更改表的定义
ALTER TABLE [ IF EXISTS ] [ ONLY ]name
[ * ]action
[, ... ] ALTER TABLE [ IF EXISTS ] [ ONLY ]name
[ * ] RENAME [ COLUMN ]column_name
TOnew_column_name
ALTER TABLE [ IF EXISTS ] [ ONLY ]name
[ * ] RENAME CONSTRAINTconstraint_name
TOnew_constraint_name
ALTER TABLE [ IF EXISTS ]name
RENAME TOnew_name
ALTER TABLE [ IF EXISTS ]name
SET SCHEMAnew_schema
ALTER TABLE ALL IN TABLESPACEname
[ OWNED BYrole_name
[, ... ] ] SET TABLESPACEnew_tablespace
[ NOWAIT ] ALTER TABLE [ IF EXISTS ]name
ATTACH PARTITIONpartition_name
{ FOR VALUESpartition_bound_spec
| DEFAULT } ALTER TABLE [ IF EXISTS ]name
DETACH PARTITIONpartition_name
[ CONCURRENTLY | FINALIZE ] whereaction
is one of: ADD [ COLUMN ] [ IF NOT EXISTS ]column_name
data_type
[ COLLATEcollation
] [column_constraint
[ ... ] ] DROP [ COLUMN ] [ IF EXISTS ]column_name
[ RESTRICT | CASCADE ] ALTER [ COLUMN ]column_name
[ SET DATA ] TYPEdata_type
[ COLLATEcollation
] [ USINGexpression
] ALTER [ COLUMN ]column_name
SET DEFAULTexpression
ALTER [ COLUMN ]column_name
DROP DEFAULT ALTER [ COLUMN ]column_name
{ SET | DROP } NOT NULL ALTER [ COLUMN ]column_name
SET EXPRESSION AS (expression
) 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 } | SETsequence_option
| RESTART [ [ WITH ]restart
] } [...] ALTER [ COLUMN ]column_name
DROP IDENTITY [ IF EXISTS ] ALTER [ COLUMN ]column_name
SET STATISTICS {integer
| DEFAULT } 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 COMPRESSIONcompression_method
ADDtable_constraint
[ NOT VALID ] ADDtable_constraint_using_index
ALTER CONSTRAINTconstraint_name
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] VALIDATE CONSTRAINTconstraint_name
DROP CONSTRAINT [ IF EXISTS ]constraint_name
[ RESTRICT | CASCADE ] DISABLE TRIGGER [trigger_name
| ALL | USER ] ENABLE TRIGGER [trigger_name
| ALL | USER ] ENABLE REPLICA TRIGGERtrigger_name
ENABLE ALWAYS TRIGGERtrigger_name
DISABLE RULErewrite_rule_name
ENABLE RULErewrite_rule_name
ENABLE REPLICA RULErewrite_rule_name
ENABLE ALWAYS RULErewrite_rule_name
DISABLE ROW LEVEL SECURITY ENABLE ROW LEVEL SECURITY FORCE ROW LEVEL SECURITY NO FORCE ROW LEVEL SECURITY CLUSTER ONindex_name
SET WITHOUT CLUSTER SET WITHOUT OIDS SET ACCESS METHOD {new_access_method
| DEFAULT } SET TABLESPACEnew_tablespace
SET { LOGGED | UNLOGGED } SET (storage_parameter
[=value
] [, ... ] ) RESET (storage_parameter
[, ... ] ) INHERITparent_table
NO INHERITparent_table
OFtype_name
NOT OF OWNER TO {new_owner
| CURRENT_ROLE | CURRENT_USER | SESSION_USER } REPLICA IDENTITY { DEFAULT | USING INDEXindex_name
| FULL | NOTHING } andpartition_bound_spec
is: IN (partition_bound_expr
[, ...] ) | FROM ( {partition_bound_expr
| MINVALUE | MAXVALUE } [, ...] ) TO ( {partition_bound_expr
| MINVALUE | MAXVALUE } [, ...] ) | WITH ( MODULUSnumeric_literal
, REMAINDERnumeric_literal
) andcolumn_constraint
is: [ CONSTRAINTconstraint_name
] { NOT NULL | NULL | CHECK (expression
) [ NO INHERIT ] | DEFAULTdefault_expr
| GENERATED ALWAYS AS (generation_expr
) STORED | GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ (sequence_options
) ] | UNIQUE [ NULLS [ NOT ] DISTINCT ]index_parameters
| PRIMARY KEYindex_parameters
| REFERENCESreftable
[ (refcolumn
) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETEreferential_action
] [ ON UPDATEreferential_action
] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] andtable_constraint
is: [ CONSTRAINTconstraint_name
] { CHECK (expression
) [ NO INHERIT ] | UNIQUE [ NULLS [ NOT ] DISTINCT ] (column_name
[, ... ] )index_parameters
| PRIMARY KEY (column_name
[, ... ] )index_parameters
| EXCLUDE [ USINGindex_method
] (exclude_element
WITHoperator
[, ... ] )index_parameters
[ WHERE (predicate
) ] | FOREIGN KEY (column_name
[, ... ] ) REFERENCESreftable
[ (refcolumn
[, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETEreferential_action
] [ ON UPDATEreferential_action
] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] andtable_constraint_using_index
is: [ CONSTRAINTconstraint_name
] { UNIQUE | PRIMARY KEY } USING INDEXindex_name
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]index_parameters
inUNIQUE
,PRIMARY KEY
, andEXCLUDE
constraints are: [ INCLUDE (column_name
[, ... ] ) ] [ WITH (storage_parameter
[=value
] [, ... ] ) ] [ USING INDEX TABLESPACEtablespace_name
]exclude_element
in anEXCLUDE
constraint is: {column_name
| (expression
) } [ COLLATEcollation
] [opclass
[ (opclass_parameter
=value
[, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]referential_action
in aFOREIGN 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 NOT 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
约束,也可以根据需要将其添加到单个分区,即子表可以不允许空值,即使父表允许,但反之则不行。
SET EXPRESSION AS
#此形式替换生成列的表达式。列中的现有数据将被重写,所有未来的更改都将应用新的生成表达式。
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 之间设置。将其设置为 DEFAULT
将恢复为使用系统默认的统计信息目标 (default_statistics_target)。(设置为 -1 是一个过时的拼写方式,可以得到相同的结果。)有关 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 }
#此形式设置列的存储模式。这控制着该列是内联存储还是在辅助的TOAST表,以及数据是否应该被压缩。 PLAIN
必须用于固定长度的值,例如 integer
,并且是内联的,未压缩的。 MAIN
用于内联的,可压缩的数据。 EXTERNAL
用于外部的,未压缩的数据,而 EXTENDED
用于外部的,压缩的数据。 写入 DEFAULT
将存储模式设置为该列数据类型的默认模式。 EXTENDED
是大多数支持非 PLAIN
存储的数据类型的默认值。 使用 EXTERNAL
将使对非常大的 text
和 bytea
值的子字符串操作运行得更快,但代价是增加了存储空间。 请注意,ALTER TABLE ... SET STORAGE
本身不会改变表中的任何内容;它只是设置了在将来的表更新期间要采用的策略。 有关更多信息,请参见 第 65.2 节。
SET COMPRESSION compression_method
#此形式设置列的压缩方法,确定将来插入的值如何压缩(如果存储模式允许压缩的话)。 这不会导致表被重写,因此现有数据可能仍然使用其他压缩方法进行压缩。 如果表使用 pg_restore 恢复,那么所有值都将使用配置的压缩方法进行重写。 但是,当从另一个关系中插入数据(例如,通过 INSERT ... SELECT
)时,来自源表的值不一定被解压缩,因此任何以前压缩的数据可能会保留其现有的压缩方法,而不是使用目标列的压缩方法重新压缩。 支持的压缩方法是 pglz
和 lz4
。 (lz4
仅在构建 PostgreSQL 时使用了 --with-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
。 这需要完全扫描表以验证列(s) 不包含空值。 在所有其他情况下,这是一个快速操作。
如果提供了约束名称,则索引将被重命名以匹配约束名称。 否则,约束将被命名为与索引相同。
执行此命令后,索引将被约束 “拥有”,就像索引是由常规 ADD PRIMARY KEY
或 ADD UNIQUE
命令构建的一样。 特别是,删除约束将使索引也消失。
此形式目前不支持分区表。
在需要添加新约束而又不阻塞表更新很长时间的情况下,使用现有索引添加约束可能会有所帮助。 为此,使用 CREATE UNIQUE INDEX CONCURRENTLY
创建索引,然后使用此语法将其转换为约束。 请参见下面的示例。
ALTER CONSTRAINT
#此形式更改先前创建的约束的属性。 目前,只有外键约束可以被更改。
VALIDATE CONSTRAINT
#此形式通过扫描表以确保没有不满足约束的行,来验证先前创建为 NOT VALID
的外键或检查约束。 如果约束已标记为有效,则不会发生任何事情。 (有关此命令用处的说明,请参见下面的 说明。)
此命令获取 SHARE UPDATE EXCLUSIVE
锁。
DROP CONSTRAINT [ IF EXISTS ]
#此形式删除表上指定的约束,以及任何作为约束基础的索引。 如果指定了 IF EXISTS
并且约束不存在,则不会引发错误。 在这种情况下,将发出通知。
DISABLE
/ENABLE [ REPLICA | ALWAYS ] TRIGGER
#这些形式配置属于表的触发器(s) 的触发。 禁用的触发器仍然为系统所知,但在其触发事件发生时不会被执行。 (对于延迟触发器,启用状态是在事件发生时检查,而不是在触发器函数实际执行时检查。) 可以禁用或启用单个触发器(按名称指定),也可以禁用或启用表上的所有触发器,或者仅禁用或启用用户触发器(此选项不包括内部生成的约束触发器,例如用于实现外键约束或可延迟唯一性和排斥约束的触发器)。 禁用或启用内部生成的约束触发器需要超级用户权限;应该谨慎操作,因为如果触发器未被执行,当然无法保证约束的完整性。
触发器触发机制还会受到配置变量 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
#此形式通过使用指示的访问方法重写表来更改表的访问方法;指定 DEFAULT
将选择设置为 default_table_access_method 配置参数的访问方法。有关更多信息,请参阅 第 61 章。
当应用于分区表时,没有数据需要重写,但之后创建的分区将默认使用给定的访问方法,除非被 USING
子句覆盖。指定 DEFAULT
会删除以前的值,导致未来的分区默认使用 default_table_access_method
。
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
的形式之一来完成。对于与规划程序相关的参数,更改将在下次锁定表时生效,因此当前正在执行的查询不会受到影响。
将为 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
创建)的那些约束,这些约束将被忽略;所有匹配的子表约束不能标记为不可继承。当前 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 VALUES partition_bound_spec
| DEFAULT }
#此形式将现有表(它本身可能已分区)附加为目标表的 partition。可以使用 FOR VALUES
将表附加为特定值的 partition,或者可以使用 DEFAULT
将表附加为默认 partition。对于目标表中的每个索引,将在附加的表中创建一个相应的索引;或者,如果已经存在等效的索引,它将被附加到目标表的索引,就好像执行了 ALTER INDEX ATTACH PARTITION
一样。请注意,如果现有表是外部表,则如果目标表上有 UNIQUE
索引,则目前不允许将表附加为目标表的 partition。(另请参阅 CREATE FOREIGN TABLE。)对于目标表中存在的每个用户定义的行级触发器,将在附加的表中创建一个相应的触发器。
使用 FOR VALUES
的 partition 使用与 CREATE TABLE
相同的语法用于 partition_bound_spec
。partition 边界规范必须对应于目标表的 partition 策略和 partition key。要附加的表必须具有与目标表相同的所有列,不得有更多列;此外,列类型也必须匹配。此外,它必须具有目标表的所有 NOT NULL
和 CHECK
约束。目前 FOREIGN KEY
约束不被考虑。将创建父表中的 UNIQUE
和 PRIMARY KEY
约束,如果它们还不存在。如果要附加的表的任何 CHECK
约束被标记为 NO INHERIT
,则命令将失败;此类约束必须在没有 NO INHERIT
子句的情况下重新创建。
如果新分区是一个常规表,则会执行完整表扫描以检查表中现有的行是否违反分区约束。可以通过在运行此命令之前向表添加有效的 CHECK
约束来避免此扫描,该约束仅允许满足所需分区约束的行。 CHECK
约束将用于确定是否需要扫描表以验证分区约束。但是,如果任何分区键都是表达式,并且分区不接受 NULL
值,则此方法无效。如果要附加一个不接受 NULL
值的列表分区,请也向分区键列添加 NOT NULL
约束,除非它是表达式。
如果新分区是一个外部表,则不会做任何操作来验证外部表中的所有行是否都遵守分区约束。(有关外部表约束的讨论,请参见 CREATE FOREIGN TABLE)。
当表具有默认分区时,定义新的分区会更改默认分区的分区约束。默认分区不能包含任何需要移动到新分区的行,并且将被扫描以验证是否存在任何这样的行。此扫描(与新分区的扫描类似)可以通过添加适当的 CHECK
约束来避免。同样,类似于新分区的扫描,当默认分区是外部表时,它总是会被跳过。
附加分区会获取父表上的 SHARE UPDATE EXCLUSIVE
锁,以及要附加的表和默认分区(如果有)上的 ACCESS EXCLUSIVE
锁。
如果要附加的表本身是分区表,则还必须对所有子分区持有其他锁。同样,如果默认分区本身是分区表,也是如此。可以通过添加 CHECK
约束来避免对子分区的锁定,如 第 5.12.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.15 节)。
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 操作隐藏。表中后续的插入和更新操作将为该列存储一个 null 值。因此,删除列速度很快,但它不会立即减小表的磁盘大小,因为已删除列所占用的空间不会被回收。该空间会在现有行更新时随着时间的推移而被回收。
要强制立即回收已删除列所占用的空间,可以执行 ALTER TABLE
的表格之一,该表格会对整个表进行重写。这将重建每一行,并将已删除的列替换为 null 值。
重写表格 ALTER TABLE
不是 MVCC 安全的。在表重写之后,如果并发事务使用重写发生之前的快照,那么该表将对这些事务显示为空。有关更多详细信息,请参见 第 13.6 节。
SET DATA TYPE
的 USING
选项实际上可以指定任何包含行旧值的表达式;也就是说,它可以引用其他列以及要转换的列。这允许使用 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 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 值。
要添加一个具有非 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;
要向一个列添加一个非 null 约束
ALTER TABLE distributors ALTER COLUMN street SET NOT NULL;
要从一个列中删除一个非 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
符合 SQL 标准。其他表格是 PostgreSQL 对 SQL 标准的扩展。此外,在单个 sequence_option
ALTER TABLE
命令中指定多个操作的能力也是一种扩展。
ALTER TABLE DROP COLUMN
可用于删除表的唯一列,从而留下一个零列表。这是对 SQL 的扩展,SQL 不允许零列表。
如果您在文档中看到任何不正确的内容,不符合您对特定功能的体验,或者需要进一步澄清,请使用 此表格 报告文档问题。