PostgreSQL DELETE 实用教程(常用语法 + 安全删除 + 易错点)
DELETE 基本语法
DELETE FROM 表名
WHERE 条件;
WHERE 条件;
-- 删除 id = 10 的记录
DELETE FROM users WHERE id = 10;
-- 删除状态为 0 且 30 天前创建的记录
DELETE FROM users WHERE status = 0 AND create_time < NOW() - INTERVAL '30 days';
注意
高危:没有 WHERE 的 DELETE 会删除整个表中的所有数据。必须先确认条件,并尽量先用 SELECT 验证目标结果。
DELETE 也能配合 RETURNING
-- 删除后返回被删记录
DELETE FROM users WHERE id = 100 RETURNING id, name, status;
RETURNING 在 PostgreSQL 中非常实用,用于审计、日志记录和回滚前确认。
信息
如果未命中任何行,RETURNING 返回空结果集,且受影响行数为 0。
DELETE ... USING:关联表删除
当删除条件依赖其他表时,可通过 USING 关联过滤。
-- 删除与某个用户无关的旧日志
DELETE FROM user_log ul USING users u WHERE ul.user_id = u.id AND u.deleted_at IS NOT NULL;
注意
易错:如果 DELETE 语句里有多张表,确保目标表和关联表的过滤条件明确,不要混淆“删除目标表”与“被关联表”。
DELETE + 子查询
-- 删除没有订单的用户
DELETE FROM users u WHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id );
信息
对于“查找没有关联记录”的场景,通常优先使用 NOT EXISTS,比 NOT IN 更稳定,也规避了 NULL 造成的隐性问题。
删除前先看数据
-- 先查看大概 率要删的记录
SELECT * FROM users WHERE status = 0 AND create_time < NOW() - INTERVAL '365 days';
-- 再执行删除
DELETE FROM users WHERE status = 0 AND create_time < NOW() - INTERVAL '365 days';
注意
生产环境中删除、更新、修改都应该“先读后写”:用 SELECT 先确认数据范围,确保条件命中的是想删的那批记录。
事务与回滚
BEGIN;
DELETE FROM user_log WHERE created_at < NOW() - INTERVAL '180 days';
-- 确认行数正确后再提交,或者执行
ROLLBACK 取消删除 COMMIT;
信息
批量删除往往伴随大量行锁与事务日志;在大表上要避免一次删太多,并考虑使用分批删除。
TRUNCATE 与 DELETE 的区别
| 操作 | 特点 | 适用场景 |
|---|---|---|
| DELETE | 按条件删除,可回滚,逐行删除 | 删除少量/按条件删除 |
| TRUNCATE | 快速清空表,不能带 WHERE 条件,通常更快 | 彻底清空整表,通常需要谨慎 |
-- 清空整个表(谨慎)
TRUNCATE TABLE temp_data;
注意
TRUNCATE 不是条件删除,不可用于“删除部分数据”,而且通常不能在事务中和某些引用关系下随意使用。
DELETE 常见坑
- 1. 忘记
WHERE,删除整表;要先 SELECT 复核。 - 2.
NOT IN子查询里出现 NULL 时容易“误删不删都不对”;优先NOT EXISTS。 - 3. 大批量删除时没有分批,可能锁表很久,影响业务。
- 4. 误删引用数据时,外键约束会阻止或触发级联行为,需要先设计好删除策略。
总结:DELETE 高频易错清单
- 1. 永远先 SELECT,再 DELETE。
- 2. 任何大批量删除都应考虑事务和分批策略。
- 3. 关联删除用
DELETE ... USING或子查询,条件要清晰。 - 4.
RETURNING可用于审计和回滚前确认。 - 5.
TRUNCATE适合清空整表,不适合按条件删除。