PostgreSQL INSERT 实用教程(常用语法 + 事务安全 + 易错点)
INSERT 基本语法
INSERT INTO 表名 (列1, 列2, ...)
VALUES (值1, 值2, ...);
VALUES (值1, 值2, ...);
-- 单行插入
INSERT INTO users (id, name, age, status) VALUES (1, 'Alice', 28, 1);
-- 插入时忽略列名:按表定义顺序插入
INSERT INTO users VALUES (2, 'Bob', 30, 1, '2025-01-01 10:00:00');
注意
不推荐“按默认顺序写 VALUES”,因为表结构调整后会导致插入错误,难以维护。
多行插入
-- 一条语句插入多行
INSERT INTO users (name, age, status) VALUES ('Tom', 18, 1), ('Jerry', 24, 0), ('Lucy', 31, 1);
多行插入比循环插入更高效,适合批量录入。
信息
事务中一次插入多行能减少提交次数,适合大批量导入;但过大的单次事务可能导致锁等待和日志膨胀。
插入默认值与 NULL
-- 使用列默认值
INSERT INTO users (name, status) VALUES ('Kate', DEFAULT);
-- 显式插入 NULL
INSERT INTO users (name, phone) VALUES ('David', NULL);
-- 省略某列:如果该列允许 NULL / 有默认值,可自动填充
INSERT INTO users (name) VALUES ('Emma');
注意
不能把字符串 'NULL' 当作 NULL 值来插入;如果列定义了 NOT NULL、CHECK、外键或唯一约束,值必须满足要求。
INSERT ... SELECT:从其他表导入
-- 从另一个表复制数据
INSERT INTO users_archive (id, name, age) SELECT id, name, age FROM users WHERE status = 0;
-- 只插入部分列,做 字段映射
INSERT INTO member_log (member_id, created_at, action) SELECT id, create_time, 'login' FROM users WHERE last_login_time IS NOT NULL;
信息
INSERT ... SELECT 非常适合做归档、同步和数据清洗。执行前通常先用 SELECT 验证目标结果行数和字段值。
RETURNING:直接拿到插入结果
-- 插入后返回主键和字段值
INSERT INTO users (name, age, status) VALUES ('Nancy', 27, 1) RETURNING id, name, status;
在 PostgreSQL 中,RETURNING 非常实用,可直接用于应用层生成新记录的 ID 或状态。
注意
如果插入失败,RETURNING 不会返回任何结果;错误原因应从数据库报错中读取。
ON CONFLICT:有则更新,无则插入(UPSERT)
适合“存在则更新,不存在则插入”的业务场景。
-- 假设 user_id 有唯一索引
INSERT INTO user_profile (user_id, nickname, updated_at) VALUES (1001, 'Tommy', NOW()) ON CONFLICT (user_id) DO UPDATE SET nickname = EXCLUDED.nickname, updated_at = NOW();
注意
关键条件:必须有唯一约束/唯一索引对应目标列,否则 ON CONFLICT 无法生效。没有唯一约束时,插入重复数据仍可能失败。
如果要忽略冲突而不报错,可使用:
INSERT INTO user_profile (user_id, nickname) VALUES (1001, 'Tommy') ON CONFLICT (user_id) DO NOTHING;
INSERT 与事务
BEGIN;
INSERT INTO users (name, age, status) VALUES ('Zoe', 29, 1);
INSERT INTO user_log (user_id, action) VALUES (currval('users_id_seq'), 'created');
COMMIT;
信息
一组相关插入最好放在一个事务中:要么全部成功,要么全部回滚。否则插入用户但日志没写入会产生脏数据。
注意
如果事务中间有异常,通常需要执行 ROLLBACK,不能继续假定前面插入成功。
常见错误与最佳实践
| 问题 | 说明 | 建议 |
|---|---|---|
| 列名写错 | 会直接报错,插入失败 | 优先明确列列表,减少歧义 |
| 唯一约束冲突 | 重复主键/唯一索引导致失败 | 使用 ON CONFLICT 或先检查 |
| NULL / 默认值混淆 | NULL 与未赋值不是同一回事 | 按列定义的允许性选择 |
| 批量插入过大 | 事务日志和锁资源压力增大 | 分批执行、控制每批大小 |
总结:INSERT 高频易错清单
- 1. 优先写出列名,避免依赖表结构顺序。
- 2. 多行插入比循环单行更高效,适合批量录入。
- 3. 使用
INSERT ... SELECT处理数据归档和同步。 - 4.
RETURNING能直接拿到插入后的 ID / 值。 - 5. 唯一冲突时优先考虑
ON CONFLICT。 - 6. 事务中相关插入要一起提交或回滚,避免半成功状态。
- 7. 大批量插入要分批,避免锁和日志压力过大。