在理想世界里,我们会在项目开始时就完美地设计好所有数据表,然后一劳永逸。但现实是,需求总在不断变化。
“我们需要给用户增加一个手机号字段。”
“订单表需要记录发货状态。”
“我们决定 username 不再需要唯一了。”
当遇到这些情况时,我们总不能删掉原来的表再重建一个吧?(那数据就全丢了!)这时,ALTER TABLE 命令就成了我们的救星。
ALTER TABLE 是一个功能极其丰富的命令集,它允许我们在不丢失数据的前提下,对现有表的结构进行各种“外科手术”:添加、删除、修改列,甚至是添加和删除约束。
警告 :在生产环境的数据库上执行 ALTER TABLE 是一个高风险操作。根据操作的类型和表的大小,它可能会锁定表,导致应用暂时无法访问,甚至可能需要很长的执行时间。在执行前,请务必了解其影响,并最好在业务低峰期进行。
准备工作
我们继续使用上一章创建的 users 表。
-- 回顾一下 users 表的结构
-- \d users (在 psql 中)
-- Table "public.users"
-- Column | Type | Collation | Nullable | Default
-- ----------+------------------------+-----------+----------+------------------------------------
-- user_id | integer | | not null | nextval('users_user_id_seq'::regclass)
-- username | character varying(50) | | not null |
-- email | character varying(100) | | not null |
-- age | integer | | |
-- Indexes:
-- "users_pkey" PRIMARY KEY, btree (user_id)
-- "users_email_key" UNIQUE CONSTRAINT, btree (email)
-- "users_username_key" UNIQUE CONSTRAINT, btree (username)
-- Check constraints:
-- "users_age_check" CHECK (age >= 18)
18.1 添加、删除、修改列
添加新列 (ADD COLUMN)
最常见的需求:给 users 表增加一个 phone_number 字段。
ALTER TABLE users
ADD COLUMN phone_number VARCHAR(20);
执行后,users 表的每一行都会多出一个 phone_number 列,其默认值为 NULL。
你也可以在添加列的同时,为它指定一个默认值 (DEFAULT)。这对于那些已经有数据的表非常有用。
ALTER TABLE users
ADD COLUMN registration_date DATE DEFAULT CURRENT_DATE;
这条命令会添加一个 registration_date 列,并且表中所有现有行的该字段都会被自动填充为今天的日期。
删除列 (DROP COLUMN)
这是一个危险操作! 删除列会永久地移除该列及其所有数据,且通常无法恢复。
假设我们后来觉得 age 这个字段不合适,决定去掉它。
ALTER TABLE users
DROP COLUMN age;
执行后,age 列以及与之关联的 CHECK (age >= 18) 约束都会被一并删除。
修改列 (ALTER COLUMN)
修改列可以做很多事,比如更改数据类型、设置/删除默认值、添加/删除 NOT NULL 约束。
1. 更改数据类型 (TYPE)
假设我们发现 phone_number 的 VARCHAR(20) 不够用,想改成 VARCHAR(30)。
ALTER TABLE users
ALTER COLUMN phone_number TYPE VARCHAR(30);
注意:不是所有类型之间都能随意转换的。比如,将一个包含文本的 VARCHAR 列转成 INT 列通常会失败。
2. 添加 NOT NULL 约束
我们决定 phone_number 必须是必填项。
-- 首先,确保所有现有行的 phone_number 都不是 NULL
UPDATE users SET phone_number = 'N/A' WHERE phone_number IS NULL;
-- 然后,添加 NOT NULL 约束
ALTER TABLE users
ALTER COLUMN phone_number SET NOT NULL;
如果表里已经有 NULL 值,直接添加 NOT NULL 会失败。
3. 删除 NOT NULL 约束
ALTER TABLE users
ALTER COLUMN phone_number DROP NOT NULL;
4. 设置/删除默认值 (DEFAULT)
-- 设置默认值
ALTER TABLE users
ALTER COLUMN age SET DEFAULT 18;
-- 删除默认值
ALTER TABLE users
ALTER COLUMN age DROP DEFAULT;
18.2 添加和删除约束
我们也可以在表创建后,动态地添加和删除约束。
添加约束 (ADD CONSTRAINT)
给约束起一个明确的名字是一个非常好的习惯。
1. 添加 UNIQUE 约束
假设我们想给 phone_number 也加上唯一约束。
ALTER TABLE users
ADD CONSTRAINT unique_phone_number UNIQUE (phone_number);
- unique_phone_number 是我们给这个约束起的名字。
2. 添加 CHECK 约束
ALTER TABLE users
ADD CONSTRAINT check_username_length CHECK (length(username) > 3);
3. 添加 FOREIGN KEY 约束
ALTER TABLE orders
ADD CONSTRAINT fk_orders_users FOREIGN KEY (user_id) REFERENCES users(user_id);
删除约束 (DROP CONSTRAINT)
删除约束就需要用到我们给它起的名字了。
-- 删除我们刚刚创建的唯一约束
ALTER TABLE users
DROP CONSTRAINT unique_phone_number;
-- 删除主键约束(不常用,但可以做到)
-- ALTER TABLE users DROP CONSTRAINT users_pkey;
18.3 重命名表和列
重命名列 (RENAME COLUMN)
ALTER TABLE users
RENAME COLUMN email TO email_address;
重命名表 (RENAME TO)
ALTER TABLE users
RENAME TO app_users;
本章小结
你已经掌握了像一个经验丰富的数据库管理员(DBA)一样,对数据库结构进行维护和演进的技能。
- 我们学会了用 ADD COLUMN, DROP COLUMN, ALTER COLUMN 来灵活地管理表的列。
- 学会了用 ADD CONSTRAINT 和 DROP CONSTRAINT 来动态地调整表的规则。
- 还学会了如何重命名表和列。
ALTER TABLE 是一个强大但需要谨慎使用的工具。理解它的能力和潜在风险,是保证数据库能够随着业务发展而平滑演进的关键。
在下一章,我们将学习一个非常有趣的概念——视图 (Views)。它像一个虚拟的、只读的表,可以用来简化复杂的查询、封装业务逻辑,并提供一个安全的数据访问层。准备好学习如何创建你自己的“数据窗口”了吗?我们下一章见!