当您创建一个表并发现自己犯了一个错误,或者应用程序的需求已发生变化,您可以删除该表并重新创建它。但是,如果表中已填充数据,或者表被其他数据库对象引用(例如外键约束),这并非一个方便的选择。因此,PostgreSQL 提供了一系列命令对现有表进行修改。请注意,这在概念上不同于更改表中包含的数据:此处我们有兴趣更改表的定义或结构。
您可以
添加列
删除列
添加约束
删除约束
更改默认值
更改列数据类型
重命名列
重命名表
所有这些操作都使用 ALTER TABLE 命令执行,其参考页包含此处未提供的详细信息。
要添加列,请使用如下命令
ALTER TABLE products ADD COLUMN description text;
新列最初填入给定的任何默认值(如果您未指定 DEFAULT
子句,则为 null)。
从 PostgreSQL 11 开始,使用常量默认值添加列不再意味着执行 ALTER TABLE
语句时需要更新表中的每一行。相反,将在下次访问该行时返回默认值,并在重写表时应用该默认值,即使在大型表上,也能让 ALTER TABLE
非常快速。
但是,如果默认值不稳定(例如 clock_timestamp()
),则需要使用在执行 ALTER TABLE
时计算的值来更新每一行。为避免潜在的冗长更新操作,特别是如果您打算主要使用非默认值填充该列,最好不添加该列,使用 UPDATE
插入正确的值,然后按如下所述添加所需的默认值。
您还可以使用常用语法同时定义列上的约束
ALTER TABLE products ADD COLUMN description text CHECK (description <> '');
事实上,应用于 CREATE TABLE
中列描述的所有选项都能在此使用。但是请记住,默认值必须满足给定的约束,否则 ADD
将失败。或者,您可以在正确填充新列后稍后添加约束(请见下文)。
要删除列,请使用类似以下的命令
ALTER TABLE products DROP COLUMN description;
列中的数据将全部消失。此外,还将删除涉及该列的表约束。但是,如果该列由另一个表的外部键约束引用,PostgreSQL 不会静默删除该约束。您可以通过添加 CASCADE
来授权删除所有依赖于该列的内容
ALTER TABLE products DROP COLUMN description CASCADE;
有关此机制的通用说明,请参见 第 5.15 节。
要添加约束,请使用表约束语法。例如
ALTER TABLE products ADD CHECK (name <> ''); ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no); ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
要添加非空约束,该约束不可写为表约束,请使用此语法
ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
该约束将立即得到检查,因此在添加表数据之前,该数据必须满足约束。
要删除约束,您需要知道其名称。如果您已为此约束指定名称,那将很容易。否则,系统将分配一个生成名称,您需要找出该名称。psql 命令 \d
在此方面会有所帮助;其他界面也可能提供查看表详细信息的方法。然后,命令为表名
ALTER TABLE products DROP CONSTRAINT some_name;
(如果您正在处理类似 $2
的生成约束名称,请不要忘记需要加上双引号,以使其成为一个有效的标识符。)
与删除列一样,如果您想要删除其他内容所依赖的约束,则需要添加 CASCADE
。一个示例是外部键约束依赖于引用列上的唯一或主键约束。
这适用于除非空约束之外的所有约束类型。要删除非空约束,请使用
ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
(请记住,非空约束没有名称。)
要为列设定一个新默认值,请使用类似以下的命令
ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
请注意,这不会影响表中任何现有行,而只是更改未来 INSERT
命令的默认值。
要删除任何默认值,请使用
ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
这实际上与将默认值设为空相同。结果,在原本没有定义默认值的情况下删除默认值不会造成错误,因为默认值隐式为 null 值。
若要将列转换为不同的数据类型,请使用类似的命令
ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
这仅在列中可以将每个现有条目通过隐式转换转换为新类型的情况下才会成功。如果需要更复杂的转换,则可以添加USING
子句,该子句指定如何从旧值计算新值。
PostgreSQL将尝试将列的默认值(如果有)转换为新类型,以及涉及该列的任何约束。但,这些转换可能会失败或会产生意外结果。通常最好在更改列的类型之前取消对列的所有约束,然后在之后再添加适当修改后的约束。