PostgreSQL 入门学习教程,从入门到精通,PostgreSQL 16 插入、更新与删除数据 —语法详解与实战案例(8)
·
PostgreSQL 16 插入、更新与删除数据 —语法详解与实战案例
一、插入数据(INSERT)
1.1 为表的所有字段插入数据
语法格式:
INSERT INTO table_name
VALUES (value1, value2, ..., valueN);
✅ 说明:必须按表结构定义的字段顺序提供所有字段的值,且数量必须完全匹配。
案例代码:
-- 创建示例表 students
CREATE TABLE students (
id SERIAL PRIMARY KEY, -- 自增主键
name VARCHAR(50) NOT NULL, -- 姓名,非空
age INT CHECK (age >= 0), -- 年龄,需 >= 0
grade VARCHAR(10), -- 年级
enrollment_date DATE DEFAULT CURRENT_DATE -- 入学日期,默认当前日期
);
-- 插入一条完整记录(按字段顺序:id, name, age, grade, enrollment_date)
-- 注意:id 是 SERIAL 类型,可传 NULL 或 DEFAULT,系统自动分配
INSERT INTO students
VALUES (DEFAULT, '张三', 18, '高一', '2025-09-01');
-- 插入另一条记录,enrollment_date 使用默认值
INSERT INTO students
VALUES (DEFAULT, '李四', 17, '高二', DEFAULT);
-- 查询验证
SELECT * FROM students;
📌 注释:
SERIAL是 PostgreSQL 的自增整型,等价于INTEGER+SEQUENCE。DEFAULT关键字用于使用字段默认值。- 若字段有默认值或允许 NULL,可省略值,但此处为“所有字段”,必须显式提供(可用 DEFAULT 或 NULL)。
1.2 为表的指定字段插入数据
语法格式:
INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN);
✅ 说明:只插入指定字段,未指定字段若允许 NULL 或有 DEFAULT,则自动填充;否则报错。
案例代码:
-- 只插入 name 和 age,其他字段使用默认值或 NULL(若允许)
INSERT INTO students (name, age)
VALUES ('王五', 16);
-- 插入 name, age, grade,enrollment_date 使用默认值
INSERT INTO students (name, age, grade)
VALUES ('赵六', 19, '高三');
-- 插入时指定字段顺序可与表结构不同,但值顺序必须对应
INSERT INTO students (grade, name, age)
VALUES ('高一', '孙七', 15);
-- 查询验证
SELECT * FROM students;
📌 注释:
- 字段列表顺序可任意,但 VALUES 中的值顺序必须与之对应。
- 未指定字段:
- 若有
DEFAULT→ 使用默认值- 若允许
NULL→ 填充 NULL- 否则 → 报错(如 NOT NULL 且无默认值)
1.3 同时插入多条记录
语法格式:
INSERT INTO table_name [(column_list)]
VALUES
(value_set1),
(value_set2),
...,
(value_setN);
✅ 说明:一次 INSERT 可插入多行,提高效率,减少网络往返。
案例代码:
-- 一次性插入三条记录,指定字段
INSERT INTO students (name, age, grade)
VALUES
('周八', 16, '高一'),
('吴九', 17, '高二'),
('郑十', 18, '高三');
-- 不指定字段,插入完整记录(注意顺序和数量)
INSERT INTO students
VALUES
(DEFAULT, '钱十一', 15, '高一', '2025-09-05'),
(DEFAULT, '冯十二', 16, '高一', DEFAULT);
-- 查询验证
SELECT * FROM students;
📌 注释:
- 多行 VALUES 用逗号分隔,每行用括号包裹。
- 性能优于多次单条 INSERT。
- 若某行违反约束(如唯一、检查),整条语句失败(除非使用 ON CONFLICT)。
1.4 将查询结果插入到表中(INSERT INTO … SELECT)
语法格式:
INSERT INTO target_table [(column_list)]
SELECT column1, column2, ..., columnN
FROM source_table
[WHERE condition];
✅ 说明:从其他表或查询结果中选择数据插入到目标表,字段类型和数量需兼容。
案例代码:
-- 创建另一个表:graduated_students(已毕业学生)
CREATE TABLE graduated_students (
id SERIAL PRIMARY KEY,
name VARCHAR(50),
graduation_year INT,
final_grade VARCHAR(10)
);
-- 将 students 表中 grade 为 '高三' 的学生插入到 graduated_students
INSERT INTO graduated_students (name, graduation_year, final_grade)
SELECT name, 2025, grade
FROM students
WHERE grade = '高三';
-- 查询验证
SELECT * FROM graduated_students;
-- 更复杂示例:插入时进行数据转换
INSERT INTO graduated_students (name, graduation_year, final_grade)
SELECT
UPPER(name) || '_GRAD', -- 转大写并加后缀
EXTRACT(YEAR FROM enrollment_date) + 3, -- 入学年份+3作为毕业年份
grade
FROM students
WHERE age >= 18;
-- 查询验证
SELECT * FROM graduated_students;
📌 注释:
- SELECT 的列数、顺序、类型必须与 INSERT 的目标列匹配。
- 可使用表达式、函数、常量进行数据转换。
- 支持 JOIN、GROUP BY、子查询等复杂查询结构。
二、更新数据(UPDATE)
语法格式:
UPDATE table_name
SET column1 = value1,
column2 = value2,
...
[WHERE condition];
⚠️ 警告:若省略 WHERE,将更新表中所有记录!
案例代码:
-- 将姓名为 '张三' 的学生年龄改为 19
UPDATE students
SET age = 19
WHERE name = '张三';
-- 更新多个字段:将 '李四' 的年级改为 '高三',年龄改为 18
UPDATE students
SET grade = '高三', age = 18
WHERE name = '李四';
-- 使用表达式更新:所有学生年龄 +1
UPDATE students
SET age = age + 1
WHERE grade = '高一';
-- 使用子查询更新:将入学日期早于平均日期的学生年级设为 '留级'
UPDATE students
SET grade = '留级'
WHERE enrollment_date < (
SELECT AVG(enrollment_date) FROM students
);
-- 查询验证
SELECT * FROM students;
📌 注释:
- SET 后可跟多个字段,用逗号分隔。
- 可使用当前字段值进行计算(如
age = age + 1)。- 支持子查询、函数、表达式。
- 返回受影响的行数(可通过
RETURNING *返回更新后数据)。
安全更新技巧(RETURNING):
-- 更新并返回被修改的记录
UPDATE students
SET age = 20
WHERE name = '王五'
RETURNING *; -- 返回更新后的整行
-- 只返回特定字段
UPDATE students
SET grade = '毕业生'
WHERE age >= 19
RETURNING id, name, grade;
三、删除数据(DELETE)
语法格式:
DELETE FROM table_name
[WHERE condition];
⚠️ 警告:若省略 WHERE,将删除表中所有记录!
案例代码:
-- 删除姓名为 '孙七' 的学生
DELETE FROM students
WHERE name = '孙七';
-- 删除年龄小于 16 的学生
DELETE FROM students
WHERE age < 16;
-- 删除年级为 '留级' 且入学日期早于 2025-01-01 的学生
DELETE FROM students
WHERE grade = '留级' AND enrollment_date < '2025-01-01';
-- 查询验证
SELECT * FROM students;
-- 删除并返回被删除的记录(PostgreSQL 特有)
DELETE FROM students
WHERE id = 5
RETURNING *;
-- 删除所有记录(慎用!)
-- DELETE FROM students; -- 将清空整个表
📌 注释:
- DELETE 不删除表结构,仅删除数据行。
- 支持复杂 WHERE 条件(AND/OR/IN/子查询等)。
RETURNING子句可返回被删除行,便于审计或日志记录。- 大量删除建议分批或使用
TRUNCATE(更快,但不可回滚,不触发触发器)。
四、综合案例 —— 学生管理系统数据操作
场景描述:
管理学生表,包括新生入学、信息修正、毕业转档、退学处理等。
-- 1. 批量插入新生
INSERT INTO students (name, age, grade)
VALUES
('新生A', 15, '高一'),
('新生B', 16, '高一'),
('新生C', 17, '高二');
-- 2. 修正录入错误:将 '新生A' 改名为 '张新生'
UPDATE students
SET name = '张新生'
WHERE name = '新生A';
-- 3. 年级升级:所有 '高二' 学生升为 '高三'
UPDATE students
SET grade = '高三'
WHERE grade = '高二';
-- 4. 毕业处理:将 '高三' 学生转移到 graduated_students 表
INSERT INTO graduated_students (name, graduation_year, final_grade)
SELECT name, 2025, grade
FROM students
WHERE grade = '高三';
-- 5. 从原表删除已毕业学生
DELETE FROM students
WHERE grade = '高三'
RETURNING id, name AS "已毕业学生";
-- 6. 清理无效数据:删除年龄超过 30 的异常记录(假设是录入错误)
DELETE FROM students
WHERE age > 30;
-- 7. 最终状态查询
SELECT '在校生' AS status, name, age, grade FROM students
UNION ALL
SELECT '毕业生' AS status, name, graduation_year AS age, final_grade AS grade
FROM graduated_students
ORDER BY status, name;
五、常见问题及解答
疑问1:插入记录时可以不指定字段名称吗?
✅ 可以,但有条件:
- 必须为所有字段提供值,且顺序必须与表结构定义完全一致。
- 若某字段有默认值或允许 NULL,仍需显式提供
DEFAULT或NULL。 - 若表结构变更(如新增字段),不指定字段名的 INSERT 可能失败。
推荐做法:
始终显式指定字段名,提高代码可读性、可维护性,避免表结构变更导致的错误。
-- ❌ 不推荐(脆弱,易出错)
INSERT INTO students VALUES (DEFAULT, '小明', 16, '高一', DEFAULT);
-- ✅ 推荐(健壮,清晰)
INSERT INTO students (name, age, grade) VALUES ('小明', 16, '高一');
疑问2:更新或者删除表时必须指定WHERE子句吗?
✅ 语法上不是必须,但强烈建议指定!
- 不指定 WHERE:UPDATE 会更新全表,DELETE 会删除全表。
- 生产环境中,误操作可能导致灾难性数据丢失。
- PostgreSQL 默认不阻止无 WHERE 的操作(除非配置触发器或策略)。
安全建议:
- 开发/测试环境:可先用 SELECT 验证 WHERE 条件是否正确。
- 生产环境:务必使用事务 + 备份。
- 使用 RETURNING 预览影响。
- 配置权限:限制普通用户执行无 WHERE 的 DML。
-- 危险操作示例(请勿在生产环境直接运行)
-- UPDATE students SET age = 0; -- 所有学生年龄归零!
-- DELETE FROM students; -- 清空整个表!
-- 安全做法:
BEGIN; -- 开启事务
UPDATE students SET age = 20 WHERE id = 100 RETURNING *;
-- 检查结果无误后再提交
-- COMMIT;
-- 若有误,回滚
ROLLBACK;
✅ 总结要点
| 操作 | 语法要点 | 安全建议 |
|---|---|---|
| INSERT | 可指定或不指定字段;支持多行、SELECT 插入 | 显式指定字段;检查约束 |
| UPDATE | SET 多字段;支持表达式/子查询;WHERE 必选(逻辑上) | 先 SELECT 验证条件;用 RETURNING;事务包裹 |
| DELETE | WHERE 控制范围;RETURNING 可审计 | 绝不裸奔无 WHERE;事务 + 备份;分批删除大数据 |
📘 最佳实践口诀:
“插数要明列,更删必带条;
事务保平安,返回好审计;
生产如战场,备份是王道。”
本章内容覆盖 PostgreSQL 16 中数据操作的核心语法,结合实战案例与安全建议,助你高效、安全地管理数据。
更多推荐



所有评论(0)