ALTER TABLE — 更改表定义
ALTER TABLE [ IF EXISTS ] [ ONLY ]name[ * ]action[, ... ] ALTER TABLE [ IF EXISTS ] [ ONLY ]name[ * ] RENAME [ COLUMN ]column_nameTOnew_column_nameALTER TABLE [ IF EXISTS ] [ ONLY ]name[ * ] RENAME CONSTRAINTconstraint_nameTOnew_constraint_nameALTER TABLE [ IF EXISTS ]nameRENAME TOnew_nameALTER TABLE [ IF EXISTS ]nameSET SCHEMAnew_schemaALTER TABLE ALL IN TABLESPACEname[ OWNED BYrole_name[, ... ] ] SET TABLESPACEnew_tablespace[ NOWAIT ] ALTER TABLE [ IF EXISTS ]nameATTACH PARTITIONpartition_name{ FOR VALUESpartition_bound_spec| DEFAULT } ALTER TABLE [ IF EXISTS ]nameDETACH PARTITIONpartition_name[ CONCURRENTLY | FINALIZE ] whereactionis one of: ADD [ COLUMN ] [ IF NOT EXISTS ]column_namedata_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_nameSET DEFAULTexpressionALTER [ COLUMN ]column_nameDROP DEFAULT ALTER [ COLUMN ]column_name{ SET | DROP } NOT NULL ALTER [ COLUMN ]column_nameSET EXPRESSION AS (expression) ALTER [ COLUMN ]column_nameDROP EXPRESSION [ IF EXISTS ] ALTER [ COLUMN ]column_nameADD 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_nameDROP IDENTITY [ IF EXISTS ] ALTER [ COLUMN ]column_nameSET STATISTICS {integer| DEFAULT } ALTER [ COLUMN ]column_nameSET (attribute_option=value[, ... ] ) ALTER [ COLUMN ]column_nameRESET (attribute_option[, ... ] ) ALTER [ COLUMN ]column_nameSET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT } ALTER [ COLUMN ]column_nameSET COMPRESSIONcompression_methodADDtable_constraint[ NOT VALID ] ADDtable_constraint_using_indexALTER CONSTRAINTconstraint_name[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ] ALTER CONSTRAINTconstraint_name[ INHERIT | NO INHERIT ] VALIDATE CONSTRAINTconstraint_nameDROP CONSTRAINT [ IF EXISTS ]constraint_name[ RESTRICT | CASCADE ] DISABLE TRIGGER [trigger_name| ALL | USER ] ENABLE TRIGGER [trigger_name| ALL | USER ] ENABLE REPLICA TRIGGERtrigger_nameENABLE ALWAYS TRIGGERtrigger_nameDISABLE RULErewrite_rule_nameENABLE RULErewrite_rule_nameENABLE REPLICA RULErewrite_rule_nameENABLE ALWAYS RULErewrite_rule_nameDISABLE ROW LEVEL SECURITY ENABLE ROW LEVEL SECURITY FORCE ROW LEVEL SECURITY NO FORCE ROW LEVEL SECURITY CLUSTER ONindex_nameSET WITHOUT CLUSTER SET WITHOUT OIDS SET ACCESS METHOD {new_access_method| DEFAULT } SET TABLESPACEnew_tablespaceSET { LOGGED | UNLOGGED } SET (storage_parameter[=value] [, ... ] ) RESET (storage_parameter[, ... ] ) INHERITparent_tableNO INHERITparent_tableOFtype_nameNOT OF OWNER TO {new_owner| CURRENT_ROLE | CURRENT_USER | SESSION_USER } REPLICA IDENTITY { DEFAULT | USING INDEXindex_name| FULL | NOTHING } andpartition_bound_specis: IN (partition_bound_expr[, ...] ) | FROM ( {partition_bound_expr| MINVALUE | MAXVALUE } [, ...] ) TO ( {partition_bound_expr| MINVALUE | MAXVALUE } [, ...] ) | WITH ( MODULUSnumeric_literal, REMAINDERnumeric_literal) andcolumn_constraintis: [ CONSTRAINTconstraint_name] { NOT NULL [ NO INHERIT ] | NULL | CHECK (expression) [ NO INHERIT ] | DEFAULTdefault_expr| GENERATED ALWAYS AS (generation_expr) [ STORED | VIRTUAL ] | 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 ] [ ENFORCED | NOT ENFORCED ] andtable_constraintis: [ CONSTRAINTconstraint_name] { CHECK (expression) [ NO INHERIT ] | NOT NULLcolumn_name[ NO INHERIT ] | UNIQUE [ NULLS [ NOT ] DISTINCT ] (column_name[, ... ] [,column_nameWITHOUT OVERLAPS ] )index_parameters| PRIMARY KEY (column_name[, ... ] [,column_nameWITHOUT OVERLAPS ] )index_parameters| EXCLUDE [ USINGindex_method] (exclude_elementWITHoperator[, ... ] )index_parameters[ WHERE (predicate) ] | FOREIGN KEY (column_name[, ... ] [, PERIODcolumn_name] ) REFERENCESreftable[ (refcolumn[, ... ] [, PERIODrefcolumn] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETEreferential_action] [ ON UPDATEreferential_action] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ] andtable_constraint_using_indexis: [ CONSTRAINTconstraint_name] { UNIQUE | PRIMARY KEY } USING INDEXindex_name[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]index_parametersinUNIQUE,PRIMARY KEY, andEXCLUDEconstraints are: [ INCLUDE (column_name[, ... ] ) ] [ WITH (storage_parameter[=value] [, ... ] ) ] [ USING INDEX TABLESPACEtablespace_name]exclude_elementin anEXCLUDEconstraint is: {column_name| (expression) } [ COLLATEcollation] [opclass[ (opclass_parameter=value[, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]referential_actionin aFOREIGN KEY/REFERENCESconstraint 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。对于生成的虚拟列,不需要 ANALYZE,因为这类列从不具有统计信息。
SET/DROP DEFAULT #这些形式设置或删除列的默认值(删除等同于将默认值设置为 NULL)。新的默认值仅适用于后续的 INSERT 或 UPDATE 命令;它不会导致表中已有的行发生更改。
SET/DROP NOT NULL #这些形式更改列是否被标记为允许 NULL 值或拒绝 NULL 值。
SET NOT NULL 仅可应用于满足以下条件的列:表中没有任何记录包含该列的 NULL 值。通常,这会在 ALTER TABLE 期间通过扫描整个表来检查,除非指定了 NOT VALID;然而,如果存在一个有效的 CHECK 约束(并且在同一命令中未删除),该约束证明不会出现 NULL,则将跳过表扫描。如果列具有无效的非空约束,则 SET NOT NULL 将对其进行验证。
如果此表是分区表,则无法对标记为 NOT NULL 的父表中的列执行 DROP NOT NULL。要删除所有分区中的 NOT NULL 约束,请在父表上执行 DROP NOT NULL。即使父表上没有 NOT NULL 约束,也可以根据需要将其添加到单个分区中;也就是说,子分区可以禁止 null 值,即使父分区允许,反之则不行。也可以仅从父表 ONLY 删除 NOT NULL 约束,这不会从子分区中删除它。
SET EXPRESSION AS #此形式替换生成列的表达式。存储的生成列中的现有数据将被重写,并且所有未来的更改都将应用新的生成表达式。
当此形式用于存储的生成列时,其统计信息将被删除,因此建议稍后在表上运行 ANALYZE。对于虚拟生成列,不需要 ANALYZE,因为这类列从不具有统计信息。
DROP EXPRESSION [ IF EXISTS ] #此形式将存储的生成列转换为普通的基准列。列中的现有数据将被保留,但未来的更改将不再应用生成表达式。
此形式目前仅支持存储的生成列(不支持虚拟的)。
如果指定了 DROP EXPRESSION IF EXISTS 且该列不是生成列,则不会抛出错误。在这种情况下,会发出通知。
ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITYSET GENERATED { ALWAYS | BY DEFAULT }DROP IDENTITY [ IF EXISTS ] #这些形式更改列是否为标识列,或更改现有标识列的生成属性。有关详细信息,请参阅 CREATE TABLE。与 SET DEFAULT 类似,这些形式仅影响后续 INSERT 和 UPDATE 命令的行为;它们不会导致表中已有的行发生更改。
如果指定了 DROP IDENTITY IF EXISTS 且该列不是标识列,则不会抛出错误。在这种情况下,会发出通知。
SET sequence_optionRESTART #这些形式修改现有标识列的基础序列。 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 } #此形式设置列的存储模式。这控制是内联存储还是在辅助表中存储该列,以及数据是否应被压缩。TOASTPLAIN 必须用于固定长度值,如 integer,它是内联、未压缩的。MAIN 用于内联、可压缩数据。EXTERNAL 用于外部、未压缩数据,EXTENDED 用于外部、压缩数据。写入 DEFAULT 将存储模式设置为列数据类型的默认模式。对于大多数支持非 PLAIN 存储的数据类型,EXTENDED 是默认值。使用 EXTERNAL 可以加快非常大的 text 和 bytea 值的子字符串操作的速度,但会增加存储空间。请注意,ALTER TABLE ... SET STORAGE 本身不会改变表中的任何内容;它只会设置未来表更新要遵循的策略。有关更多信息,请参阅 第 66.2 节。
SET COMPRESSION compression_method #此形式设置列的压缩方法,决定了未来插入的值将如何被压缩(如果存储模式允许压缩)。这不会导致表被重写,因此现有数据可能仍会以其他压缩方法进行压缩。如果使用 pg_restore 恢复表,那么所有值都将以配置的压缩方法重写。但是,当数据从另一个关系插入时(例如,通过 INSERT ... SELECT),源表中的值不一定会被解压,因此任何先前压缩的数据可能会保留其现有的压缩方法,而不是以目标列的压缩方法重新压缩。支持的压缩方法是 pglz 和 lz4。(只有在使用 --with-lz4 构建 PostgreSQL 时,lz4 才可用。)此外,compression_method 可以是 default,它选择默认行为,即在数据插入时咨询 default_toast_compression 设置以确定要使用的方法。
ADD table_constraint [ NOT VALID ] #此形式在表中添加一个新约束,使用与 CREATE TABLE 相同的约束语法,加上 NOT VALID 选项,该选项目前仅允许用于外键、CHECK 和非空约束。
通常,此形式将导致扫描表以验证表中所有现有行是否满足新约束。但如果使用 NOT VALID 选项,则会跳过这个可能很耗时的扫描。该约束仍然会应用于后续的插入或更新(也就是说,它们将失败,除非在引用表中存在匹配的行(对于外键),或者它们将失败,除非新行符合指定的检查条件)。但是,数据库不会假定该约束适用于表中的所有行,直到使用 VALIDATE CONSTRAINT 选项对其进行验证为止。有关使用 NOT VALID 选项的更多信息,请参阅下面的 Notes。
虽然大多数形式的 ADD 都需要 table_constraintACCESS EXCLUSIVE 锁,但 ADD FOREIGN KEY 仅需要 SHARE ROW EXCLUSIVE 锁。请注意,ADD FOREIGN KEY 除了在声明约束的表上获取锁外,还会获取引用表上的 SHARE ROW EXCLUSIVE 锁。
当向分区表添加唯一或主键约束时,会应用其他限制;请参阅 CREATE TABLE。
ADD table_constraint_using_index #此形式根据现有唯一索引在表中添加新的 PRIMARY KEY 或 UNIQUE 约束。索引的所有列都将包含在约束中。
该索引不能包含表达式列,也不能是部分索引。此外,它必须是一个具有默认排序顺序的 b-tree 索引。这些限制确保该索引等同于通过常规 ADD PRIMARY KEY 或 ADD UNIQUE 命令构建的索引。
如果指定了 PRIMARY KEY,并且索引的列尚未标记为 NOT NULL,那么此命令将尝试对每个这样的列执行 ALTER COLUMN SET NOT NULL。这需要进行完整的表扫描来验证列不包含 null 值。在所有其他情况下,这是一个快速操作。
如果提供了约束名称,则索引将重命名为与约束名称匹配。否则,约束将与索引同名。
执行此命令后,该索引将像通过常规 ADD PRIMARY KEY 或 ADD UNIQUE 命令构建的索引一样被约束 “拥有”。特别是,删除约束也将使索引消失。
此形式目前不支持分区表。
使用现有索引添加约束在需要添加新约束而又不想长时间阻止表更新的情况下很有帮助。为此,可以使用 CREATE UNIQUE INDEX CONCURRENTLY 创建索引,然后使用此语法将其转换为约束。请参阅下面的示例。
ALTER CONSTRAINT #此形式修改先前创建的约束的属性。目前只有外键约束可以通过这种方式修改,但请参阅下文。
ALTER CONSTRAINT ... INHERITALTER CONSTRAINT ... NO INHERIT #这些形式修改一个可继承约束,使其变为不可继承,或反之。目前只能以这种方式修改非空约束。除了更改约束的可继承状态外,当一个不可继承约束被标记为可继承时,如果表有子表,则等效的约束将被添加到子表中。当将一个可继承约束标记为不可继承时,如果在有子表的表上执行,则子表上的相应约束将被标记为不再继承,但不会被删除。
VALIDATE CONSTRAINT #此形式通过扫描表以确保没有不满足约束的行,来验证先前创建为 NOT VALID 的外键、检查或非空约束。如果约束被设置为 NOT ENFORCED,则会抛出错误。如果约束已被标记为有效,则什么也不做。(有关此命令用处的解释,请参阅下面的 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 以便在副本上也触发可能很合适。
当此命令应用于分区表时,相应分区克隆触发器的状态也会被更新,除非指定了 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 配置参数设置的访问方法。有关更多信息,请参阅 第 62 章。
当应用于分区表时,没有数据需要重写,但之后创建的分区将默认为给定的访问方法,除非被 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 #此形式将目标表添加为指定父表的新的子表。之后,对父表的查询将包含目标表的记录。要被添加为子表,目标表必须已经包含与父表相同的列(它也可以有额外的列)。列必须具有匹配的数据类型。
此外,父表上的所有 CHECK 和 NOT NULL 约束也必须存在于子表中,除了那些被标记为非继承的(即,使用 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 } #此形式将现有表(可能本身是分区的)附加为目标表的单个分区。可以使用 FOR VALUES 将表作为特定值的分区附加,或使用 DEFAULT 作为默认分区附加。对于目标表中的每个索引,将在附加的表中创建一个对应的索引;或者,如果已存在等效索引,则将其附加到目标表的索引,如同执行了 ALTER INDEX ATTACH PARTITION 一样。请注意,如果现有表是外部表,目前不允许将该表作为目标表的单个分区附加,如果目标表上有 UNIQUE 索引的话。(另请参阅 CREATE FOREIGN TABLE。)对于目标表中存在的每个用户定义的行级触发器,将在附加的表中创建一个对应的触发器。
使用 FOR VALUES 的分区使用与 CREATE TABLE 相同的 partition_bound_spec 语法。分区边界规范必须与目标表的定义策略和分区键匹配。要附加的表必须具有与目标表相同的所有列,并且不多不少;此外,列类型也必须匹配。另外,它必须具有目标表的所有 NOT NULL 和 CHECK 约束,且未标记为 NO INHERIT。目前 FOREIGN KEY 约束不被考虑。父表中的 UNIQUE 和 PRIMARY KEY 约束将在分区中创建(如果它们尚不存在)。
如果新分区是常规表,将执行完整的表扫描以检查表中现有的行是否违反分区约束。可以通过向表中添加一个有效的 CHECK 约束来避免此扫描,该约束只允许满足所需分区约束的行在运行此命令之前。将使用 CHECK 约束来确定是否需要扫描表来验证分区约束。但是,如果任何分区键是表达式且分区不接受 NULL 值,则此方法无效。如果附加一个不接受 NULL 值的列表分区,请同时向分区键列添加 NOT NULL 约束,除非它是表达式。
如果新分区是外部表,将不会执行任何操作来验证外部表中的所有行是否符合分区约束。(有关外部表上的约束的讨论,请参阅 CREATE FOREIGN TABLE。)
当表具有默认分区时,定义新分区会更改默认分区的分区约束。默认分区不能包含任何需要移动到新分区的行,并将被扫描以验证其中没有行。此扫描(如新分区的扫描)如果存在适当的 CHECK 约束,则可以避免。同样,与新分区的扫描一样,当默认分区是外部表时,此扫描总是被跳过。
附加分区会在父表上获取一个 SHARE UPDATE EXCLUSIVE 锁,此外还会获得对要附加的表以及默认分区(如果有)的 ACCESS EXCLUSIVE 锁。
如果正在附加的表本身是分区的,则还必须持有对所有子分区的锁。同样,如果默认分区本身是分区的,也必须持有对所有子分区的锁。可以通过添加 CHECK 约束来避免对子分区的锁定,如 Section 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 #自动删除依赖于被删除列或约束的对象(例如,引用该列的视图),以及反过来依赖于这些对象的所有对象(参见 Section 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 时,默认值将在语句执行时进行评估,并将结果存储在表的元数据中,当访问任何现有行时,该结果将被返回。该值仅在表被重写时应用,这使得 ALTER TABLE 即使对于大表也非常快速。如果未指定任何列约束,则 DEFAULT 使用 NULL。在这两种情况下,都不需要重写表。
添加具有易失性 DEFAULT(例如 clock_timestamp())、已存储的生成列、标识列或具有约束的域数据类型的列将导致整个表及其索引被重写。添加虚拟生成列永远不需要重写。
更改现有列的类型通常会导致整个表及其索引被重写。作为例外,当更改现有列的类型时,如果 USING 子句不更改列内容,并且旧类型是可二进制强制转换为新类型或是不受约束的、基于新类型的域,则不需要重写表。但是,索引仍会被重建,除非系统能够验证新索引在逻辑上等同于现有索引。例如,如果更改了列的排序规则,则需要重建索引,因为新的排序顺序可能不同。但是,在没有排序规则更改的情况下,可以将列从 text 更改为 varchar(反之亦然),而无需重建索引,因为这些数据类型排序相同。
对于大表,表和/或索引的重建可能需要大量时间,并且将临时需要多达两倍的磁盘空间。
添加 CHECK 或 NOT NULL 约束需要扫描表以验证现有行是否满足约束,但不需要重写表。如果 CHECK 约束被添加为 NOT ENFORCED,则不会执行验证。
同样,在附加新分区时,可能会对其进行扫描以验证现有行是否满足分区约束。
在单个 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 安全的。在表重写之后,对于并发事务来说,表将显示为空,如果它们使用的是在重写发生之前拍摄的快照。有关更多详细信息,请参阅 Section 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),但永远不会递归到传统继承的后代表。添加约束只递归 CHECK 约束,这些约束未被标记为 NO INHERIT。
不允许更改系统目录表的任何部分。
有关有效参数的进一步说明,请参阅 CREATE TABLE。Chapter 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 [COLUMN]、DROP [COLUMN]、DROP IDENTITY、RESTART、SET DEFAULT、SET DATA TYPE(无 USING)、SET GENERATED 和 SET 形式符合 SQL 标准。sequence_optionADD 形式符合 SQL 标准,当省略 table_constraintUSING INDEX 和 NOT VALID 子句且约束类型是 CHECK、UNIQUE、PRIMARY KEY 或 REFERENCES 之一时。其他形式是 SQL 标准的 PostgreSQL 扩展。此外,能够在一个 ALTER TABLE 命令中指定多个修改也是一项扩展。
ALTER TABLE DROP COLUMN 可用于删除表的唯一列,留下一个零列表。这是 SQL 的扩展,SQL 不允许零列表。