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 EXISTS ]
#此表格将从表中删除列。还会自动删除涉及该列的索引和表约束。如果删除列将导致统计信息仅包含一列的数据,则还会删除引用已删除列的多变量统计信息。如果表外的任何内容(例如外键引用或视图)依赖于该列,则需要写 CASCADE
。如果指定了 IF EXISTS
且该列不存在,则不会引发错误。在这种情况下,将发布一条通知。
SET DATA TYPE
#此表格会更改表的列的类型。通过重新解析最初提供的表达式,将自动转换涉及该列的索引和简单表约束以使用新的列类型。可选的 COLLATE
子句指定新列的排序规则;如果省略,则排序规则会成为新列类型使用的默认排序规则。可选的 USING
子句指定如何计算旧值的新列值;如果省略,则默认转换与将旧数据类型分配为新数据类型的强制类型转换相同。如果从旧类型到新类型没有隐式强制类型转换,则必须提供 USING
子句。
当使用此表格时,列的统计信息将被删除,因此建议之后对表运行 ANALYZE
。
SET
/DROP DEFAULT
#这些表格将设置或删除列的默认值(删除等同于将默认值设置为 NULL)。新默认值仅适用于后续的 INSERT
或 UPDATE
命令;它不会导致表中已有的行更改。
设置
/删除 非空
#这些表单更改一列是标记为允许空值还是拒绝空值。
设置非空
可能只应用于没有记录在表中包含NULL
值的一列。通常这是通过扫描表检查ALTER TABLE
;但是,如果找到有效的检查
约束来证明没有NULL
存在,那么表扫描将跳过。
如果此表是分区,那么不能在父表中将列标记为非空
的情况下执行删除非空
。要从所有分区中删除非空
约束,请在父表上执行删除非空
。即使父对象上没有非空
约束,如果需要,此类约束仍可以添加到单独的分区中;也就是说,即使父对象允许空值,子元素也可以不允许空值,但不能反过来。
设置表达式
#此表单替换生成列的表达式。列中现有数据被重写,所有以后的更改将应用新的生成表达式。
删除表达式 [如果存在]
#此表单将存储生成的列变成普通基本列。列中现有数据被保留,但今后的更改将不再应用生成表达式。
如果指定删除表达式如果存在
且该列不是存储生成的列,则不会引发错误。在这种情况下,将发出通知。
添加生成 {始终 | 默认} 作为标识
设置生成 {始终 | 默认}
删除标识 [如果存在]
#这些表单更改一列是否为标识列或更改现有标识列的生成属性。有关详细信息,请参阅创建表
。与设置默认设置
类似,这些表单仅影响后续插入
和更新
命令的行为;它们不会导致表中已有的行发生更改。
如果指定删除标识如果存在
且该列不是标识列,则不会引发错误。在这种情况下,将发出通知。
设置 sequence_option
重新启动
#这些表单将更改现有标识列的基础序列。 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
。(仅在构建 PostgreSQL 时使用了 --with-lz4
时才提供 lz4
。)此外, compression_method
可以是 default
,其将在插入数据时查阅 default_toast_compression 设置以选择要使用的方法。
ADD table_constraint
[ NOT VALID ]
#此表单使用与 CREATE TABLE
相同的约束语法及选项 NOT VALID
为某个表添加新的约束,目前该选项仅适用于外键和 CHECK 约束。
通常情况下,此表单会扫描该表以验证表中所有现有行是否满足该新约束。但是,如果使用了 NOT VALID
选项,则会跳过此潜在的长扫描。仍将在后续的插入或更新操作中对约束执行强制(即,对于外键,只有在被引用的表中存在匹配行时此类操作才不会失败;对于 CHECK 约束,只有当新行与指定检查条件相同时此类操作才不会失败)。但在使用 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-tree 索引。这些限制确保索引等效于使用常规 ADD PRIMARY KEY
或 ADD UNIQUE
命令构建的索引。
如果指定 PRIMARY KEY
,并且索引的列尚未被标记为 NOT NULL
,那么此命令将尝试对每列执行 ALTER COLUMN SET NOT NULL
。这需要对表进行全扫描,以验证该列中不包含任何空值。在其他所有情况下,此操作都很快。
如果提供了约束名称,那么将把索引重命名为与约束名称相匹配的名称。否则,该约束将与索引同名。
执行此命令后,索引将以约束““归属””的方式,就如同该索引由常规 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
#这些形式配置触发器的触发,它们属于該表。已禁用的触发器仍然为系统所知,但不会在发生其触发事件时执行。(对于延迟触发器,启用状态会在事件发生时进行检查,而不是在触发器函数实际执行时进行检查。)可以禁用或启用由名称指定的一个触发器或表上的所有触发器,或者仅用户触发器(此选项不包括内部生成的约束触发器,例如用于实施外键约束或可延迟的唯一性和排除约束的那些触发器)。禁用或启用内部生成的约束触发器需要超级用户权限;在执行此操作时应该谨慎,因为如果未执行触发器,则当然无法保证约束的完整性。
触发器触发机制也受配置变量 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 }
#此表单附加现有表(本身可能被分区)作为目标表的分区。使用 FOR VALUES
可将表附加为特定值分区,或者使用 DEFAULT
将其附加为默认分区。对于目标表中的每个索引,将在附加表中创建对应的索引;或者,如果已存在同等索引,则将其附加到目标表的索引,仿佛已执行 ALTER INDEX ATTACH PARTITION
。请注意,如果现有表是外部表,则在目标表上有 UNIQUE
索引时,目前不允许将该表附加为目标表的分区。(另请参见 CREATE FOREIGN TABLE。)对于目标表中存在的每个用户定义的行级触发器,在附加表中都会创建一个对应的触发器。
使用 FOR VALUES
的分区与 CREATE TABLE
中 partition_bound_spec
的语法相同。分区限定规范必须与目标表的分区策略和分区键相对应。要附加的表必须与目标表具有相同的所有列,并且只能有这些列;此外,列类型也必须匹配。此外,它还必须具有 NOT NULL
和目标表(未标记为 NO INHERIT
)的 CHECK
约束。当前未考虑 FOREIGN KEY
约束。 UNIQUE
和 PRIMARY KEY
约束会从父表中创建到分区中(如果尚未存在)。
如果新分区是常规表,将执行全表扫描以检查表中现有的行是否违反分区约束。通过向表添加有效的 CHECK
约束可以避免此扫描,该约束仅允许满足所需的分区约束的行在运行此命令之前运行。 CHECK
约束将用于确定无需扫描该表以验证分区约束。但是,如果任何分区键都是表达式,并且分区不接受 NULL
值,则此方法不起作用。如果附加不接受 NULL
值的列表分区,还应向分区键列添加 NOT NULL
约束(除非它是表达式)。
如果新分区是外部表,则不会执行任何操作来验证外部表中的所有行是否遵循分区约束。(请参阅 CREATE FOREIGN TABLE 中有关外部表约束的讨论。)
当表具有默认分区时,定义新分区会更改默认分区的分区约束。默认分区不能包含任何需要移动到新分区中的行,并且将被扫描以验证没有这样的行。这种扫描(比如新分区的扫描)在存在适当的 CHECK
约束的情况下可以避免。与新分区的扫描一样,当默认分区是外部表时,它总是会被跳过。
附加分区时除了对当前附加的分区和默认分区(如果有)添加 ACCESS EXCLUSIVE
锁之外,还需要在父表上获取 SHARE UPDATE 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
调用。分区表中最多只能有一个分区可以一次挂起分离。
除 RENAME
、SET SCHEMA
、ATTACH PARTITION
和 DETACH PARTITION
以外,对单个表格起作用的所有 ALTER TABLE
表格,都可以合并成一起应用的多条更动的列表。例如,可以在单个命令中添加多列和/或更改多列的类型。对于大表格而言,这尤其有用,因为只需要对表格进行一次遍历。
您必须拥有该表格,才能使用 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
表达式不适用于列的默认值(如果有的话)。该结果或许并不是默认所需常量表达式。即表示当从旧类型至新类型不存在隐含或赋值转换时,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);
这将导致表中所有现有行的新列填充为空值。
添加具有非空默认值的列
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
符合 SQL 标准。其他形式是 PostgreSQL 的 SQL 标准扩展。此外,在一个 sequence_option
ALTER TABLE
命令中指定多个操作的能力也是一项扩展。
ALTER TABLE DROP COLUMN
可用于删除表的唯一列,留下一个零列表。这是 SQL 的一项扩展,它不允许零列表。