5.7. 修改表 #
创建表之后,如果你意识到自己犯了错误,或者应用需求发生了变化,可以删掉表再重新创建。但如果表中已经有数据,或者该表已被其他数据库对象引用(例如被外键约束引用),这样做就不方便了。因此,PostgreSQL 提供了一组命令来修改现有表。注意,这在概念上不同于修改表中保存的数据:这里关注的是修改表的定义,也就是表的结构。
利用这些命令,我们可以:
增加列
移除列
增加约束
移除约束
修改默认值
修改列数据类型
重命名列
重命名表
所有这些动作都由 ALTER TABLE 命令执行,其参考页面中包含更详细的信息。
5.7.1. 增加列 #
要添加一列,可以使用这样的命令:
ALTER TABLE products ADD COLUMN description text;
新列最初会填入给定的默认值(如果没有指定 DEFAULT 子句,则填入空值)。
提示
从 PostgreSQL 11 开始,添加带有常量默认值的列时,在执行 ALTER TABLE 语句时不再需要更新表中的每一行。相反,该默认值会在下一次访问该行时返回,并在表被重写时应用,因此即使面对大表,ALTER TABLE 也会非常快。
然而,如果默认值是易失性的(例如 clock_timestamp()),则每一行都需要更新为执行 ALTER TABLE 时计算出的值。为避免潜在的长时间更新操作,特别是在你本来就打算用大多数非默认值填充该列时,更好的做法可能是先添加一个没有默认值的列,用 UPDATE 填入正确的值,然后再按下文所述添加所需的默认值。
也可以同时为该列定义约束,使用常规语法:
ALTER TABLE products ADD COLUMN description text CHECK (description <> '');
实际上,凡是在 CREATE TABLE 中可用于列描述的选项,在这里都可以使用。不过要记住,默认值必须满足给定约束,否则 ADD 就会失败。另一种做法是先把新列正确填好,再在之后添加约束(见下文)。
5.7.2. 移除列 #
要删除一列,使用如下命令:
ALTER TABLE products DROP COLUMN description;
该列中的数据会消失,涉及该列的表约束也会被删除。不过,如果该列被其他表的外键约束引用,PostgreSQL 不会静默删除该约束。你可以通过添加 CASCADE 来授权删除所有依赖该列的对象:
ALTER TABLE products DROP COLUMN description CASCADE;
关于这个操作背后的一般性机制请见第 5.15 节。
5.7.3. 增加约束 #
要添加约束,可以使用表约束语法,例如:
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;
约束会立即被检查,因此必须先保证表中的数据满足约束,然后才能添加该约束。
5.7.4. 移除约束 #
要删除约束,首先需要知道它的名称。如果你在创建时给它指定了名称,这很容易;否则就需要先查出系统生成的名称。psql 命令\d
在这里会很有帮助,其他接口也可能提供查看表详细信息的方法。然后命令是:
tablename
ALTER TABLE products DROP CONSTRAINT some_name;
和删除列一样,如果要删除某些其他对象所依赖的约束,也需要加上 CASCADE。例如,外键约束就依赖于被引用列上的唯一约束或主键约束。
对于删除非空约束,则有简化语法可用:
ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
(请记住,非空约束没有名称。)
5.7.5. 更改列的默认值 #
要为一个列设置一个新默认值,使用命令:
ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
注意这不会影响表中任何已经存在的行,它只是为未来的 INSERT 命令改变了默认值。
要移除任何默认值,使用:
ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
这等同于将默认值设置为空值。相应地,试图删除一个未被定义的默认值并不会引发错误,因为默认值已经被隐式地设置为空值。
5.7.6. 修改列的数据类型 #
为了将一个列转换为一种不同的数据类型,使用如下命令:
ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
只有当列中的每一个项都能通过一个隐式类型转换为新的类型时该操作才能成功。如果需要一种更复杂的转换,应该加上一个 USING 子句来指定应该如何把旧值转换为新值。
PostgreSQL 将尝试把列的默认值(如果有)转换为新类型,其他涉及到该列的任何约束也是一样。但是这些转换可能失败或者产生奇特的结果。因此通常最好在修改类型之前先删除该列上所有的约束,然后在修改完类型后重新加上相应修改过的约束。
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.