删除重复记录时为何用max(rowid)/min(rowid?能否不用伪列rowid删除?
嘿,咱们来一步步拆解你的问题,这在处理重复数据时是非常常见的场景,我给你理得明明白白👇
1. 为什么删除重复记录时需要用max(rowid)或min(rowid)?
首先得搞懂rowid是什么——它是Oracle数据库里的伪列,简单说就是每条记录在磁盘上的唯一“身份证号”。哪怕两行数据的所有字段完全一模一样,它们的rowid也绝对不同,因为存储位置不一样。
那删除重复记录时,我们的核心需求是:保留一组重复行中的某一条,删掉其他的。这时候就需要一个能精准区分这些重复行的标识,rowid就是干这个的。
如果不用max(rowid)或min(rowid),直接写DELETE FROM table WHERE 重复条件,数据库会懵:“所有这些行都符合条件,我到底删哪条?”结果要么把所有重复行全删了,要么报错。而max(rowid)/min(rowid)就是给数据库一个明确的指令:“留下这组里rowid最大/最小的那条,剩下的都删掉”。
关于max(rowid)/min(rowid)的具体含义
max(rowid):在一组完全重复的数据行中,取磁盘存储标识最大的那一行。由于rowid通常随数据插入顺序递增,这一般就是这组重复记录里最后被插入的那条。min(rowid):反之,取磁盘存储标识最小的那一行,也就是这组重复记录里最早被插入的那条。
2. 是否可以不使用伪列rowid来删除重复记录?
当然可以!有好几种替代方案,我给你举几个常用的:
方案一:用窗口函数(最灵活)
利用ROW_NUMBER()窗口函数给每组重复行编号,然后删掉编号大于1的行。比如:
DELETE FROM your_table WHERE (col1, col2, col3) IN ( SELECT col1, col2, col3 FROM ( SELECT col1, col2, col3, -- 按重复字段分组,给每行编号,你可以自定义排序规则 ROW_NUMBER() OVER (PARTITION BY col1, col2, col3 ORDER BY create_time DESC) AS rn FROM your_table ) t WHERE rn > 1 );
这里PARTITION BY后面的是判断重复的字段,ORDER BY可以换成你想要保留的规则(比如按时间保留最新的),非常灵活。
方案二:临时表中转(适合小数据量)
先把去重后的数据导入临时表,清空原表再导回去:
-- 把去重后的数据存到临时表 CREATE TABLE temp_table AS SELECT DISTINCT * FROM your_table; -- 清空原表(注意:TRUNCATE会重置自增,有约束的话要谨慎) TRUNCATE TABLE your_table; -- 把临时表的数据导回原表 INSERT INTO your_table SELECT * FROM temp_table; -- 删除临时表 DROP TABLE temp_table;
这种方法简单粗暴,但如果是生产环境的大表,可能会锁表影响业务,所以要选合适的时机操作。
方案三:利用主键/唯一索引(如果有的话)
如果你的表有主键或者唯一索引,也可以通过分组找到重复的记录,然后删掉主键不在分组结果里的行。不过如果没有这类唯一标识,这个方法就用不了啦。
不过要提一句:用rowid的方法通常是效率最高的,因为rowid是直接对应磁盘位置的,数据库可以快速定位到要删除的行,不需要额外的计算。其他方法各有适用场景,你可以根据自己的表结构和数据量来选。
内容的提问来源于stack exchange,提问作者abhithombare45

