最稳妥的去重方案是用 rowid + group by + min(rowid);因 rowid 唯一标识物理插入顺序,而主键、时间字段等易失效;需注意 null 处理、多字段元组写法、大表索引优化及删除前校验。

直接上结论:用 ROWID + GROUP BY + MIN(ROWID) 组合是最稳妥、兼容性最好、也最容易验证的方案。别碰 ROW_NUMBER() 套子查询删表,它在某些 Oracle 版本(尤其 11g 及更早)里不支持直接对非视图/子查询结果执行 DELETE。
为什么必须用 ROWID 而不是主键或时间字段
Oracle 的 ROWID 是物理地址标识,插入顺序越早,ROWID 值越小(虽然不绝对严格递增,但实践中可视为插入先后顺序)。而主键可能被重用、时间字段可能为空或重复、自增 ID 可能跳号——这些都导致“保留最小 ID”逻辑失效。只有 ROWID 能真实反映哪条是“最早进来的那条”。
-
ROWID是 Oracle 表每行唯一且不可变的物理地址,删除前必须确认它没被其他会话修改(即别在高并发写入时跑) - 如果表有
UNIQUE或PRIMARY KEY约束,但你仍按业务字段去重(比如只看name和email),那主键字段本身不能作为去重依据 - 千万别用
ORDER BY created_time替代ORDER BY ROWID—— 时间精度不足(秒级)、时区混乱、或批量导入时时间全一样,都会让结果不可控
单字段去重:比如只按 name 判断重复
这是最常见场景。假设表叫 customer,你想按 name 去重,留 ROWID 最小的。
先查出要删哪些:
SELECT name, COUNT(*) FROM customer GROUP BY name HAVING COUNT(*) > 1;
再执行删除(注意括号和子查询结构):
DELETE FROM customer WHERE name IN ( SELECT name FROM customer GROUP BY name HAVING COUNT(*) > 1 ) AND ROWID NOT IN ( SELECT MIN(ROWID) FROM customer GROUP BY name HAVING COUNT(*) > 1 );
- 两个
GROUP BY子句必须完全一致,否则HAVING条件匹配不上,可能误删整表 -
ROWID NOT IN (...)是核心逻辑:只删那些“属于重复组,但又不是该组最小ROWID”的行 - 如果
name允许为NULL,上面语句会漏掉NULL重复项——得额外加OR name IS NULL并在子查询中处理GROUP BY name对NULL的分组行为(Oracle 默认把所有NULL归为一组)
多字段组合去重:比如按 (name, email) 判断重复
语法结构类似,但要注意字段列表写法和括号嵌套:
DELETE FROM customer WHERE (name, email) IN ( SELECT name, email FROM customer GROUP BY name, email HAVING COUNT(*) > 1 ) AND ROWID NOT IN ( SELECT MIN(ROWID) FROM customer GROUP BY name, email HAVING COUNT(*) > 1 );
- 必须用
(name, email)元组形式,不能写成name = ... AND email = ...—— 后者无法正确匹配多值重复组 - 如果其中某个字段可能为
NULL,Oracle 的IN对NULL处理是三值逻辑(UNKNOWN),会导致这部分重复数据被跳过。稳妥做法是显式补IS NULL判断,或改用EXISTS+JOIN写法 - 大表慎用:
GROUP BY在百万级以上数据时可能触发临时表空间不足,建议提前在(name, email)上建函数索引或位图索引加速
执行前必须做的三件事
这条 SQL 看似简单,但一旦出错就是不可逆的数据丢失。
- 先用
SELECT * FROM customer WHERE ...把将被删除的行完整捞出来,保存到临时表或导出文件,确认无误再删 - 确保事务未提交前不要关闭连接——
DELETE不自动提交,但断连后回滚可能失败(尤其用了数据库链接或分布式事务) - 如果表上有触发器、物化视图日志、或正在被 GoldenGate / OGG 同步,
ROWID删除可能引发异常或同步延迟,需协调 DBA 暂停相关链路
真正麻烦的从来不是 SQL 写法,而是删完发现某条“看起来重复”的记录其实带了关键上下文(比如一条是测试数据、一条是生产数据),而你只靠字段值根本分不清——这时候 ROWID 就是你唯一的救命稻草,也是你唯一能回溯的依据。











