跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

SQL如何判断记录是否为重复项_使用ROW_NUMBER标记录状态

ROW_NUMBER()仅按规则编号,识别重复需结合PARTITION BY字段与“rn>1”判断;PARTITION BY必须严格匹配业务重复定义,ORDER BY决定组内优先级,编号为1者为每组代表。 用
ROW_NUMBER()
标记重复记录的最简逻辑 直接结论:
ROW_NUMBER()
本身不判断重复,它只按规则给行编号;真正识别重复,得靠“对相同字段分组后编号 > 1”的组合逻辑。核心不是函数本身,而是
PARTITION BY
的字段是否覆盖你定义的“重复标准”。 比如你认为
user_id
和
order_date
完全相同时算重复,那
PARTITION BY user_id, order_date
就是必须项;若只按
user_id
分组,那同用户所有记录都会被编号,哪怕日期不同——这不是你想要的重复。
PARTITION BY
字段必须严格对应业务中“视为同一重复组”的条件
ORDER BY
在组内决定哪条算“第一”,通常用时间戳或主键(如
created_at DESC
保最新,
id ASC
保最早) 编号为
1
的行是每组的“代表”,其余都是重复候选——但是否真删/标为重复,还得结合业务规则再过滤 写法示例:标记重复并保留最新一条 常见需求:查出所有重复记录,但把每组里
updated_at
最大的那条标为非重复(即保留),其余标为重复。
SELECT id, user_id, order_date, updated_at, CASE WHEN rn = 1 THEN 'keep' ELSE 'duplicate' END AS status FROM ( SELECT id, user_id, order_date, updated_at, ROW_NUMBER() OVER ( PARTITION BY user_id, order_date ORDER BY updated_at DESC, id DESC ) AS rn FROM orders ) t;
注意这里
ORDER BY updated_at DESC, id DESC
是防时间相同时排序不确定;如果业务允许任意保留一条,单写
ORDER BY updated_at DESC
即可。
ROW_NUMBER()
vs
COUNT(*) OVER
:选哪个更合适? 如果只需“知道某行是否属于重复组”,
COUNT(*) OVER (PARTITION BY ...)
更直观:结果直接是组内总行数,> 1 即表示重复。 用
ROW_NUMBER()
:适合需要排序、取 Top N、或明确区分“首条/非首条”的场景 用
COUNT(*) OVER
:适合纯判断“是否重复”、且不关心组内顺序时,语义更直白,性能在大数据量下略优(少一次排序) 二者都不能替代
GROUP BY + HAVING
做聚合统计,那是另一类需求 例如只标状态,不用排序逻辑:
CASE WHEN COUNT(*) OVER (PARTITION BY user_id, order_date) > 1 THEN 'duplicate' ELSE 'unique' END
更轻量。 容易踩的坑:NULL 值和数据类型隐式转换
PARTITION BY
中字段含
NULL
时,所有
NULL
会被归为同一组——这常导致误判重复。比如
phone
为空的多条记录,会被当成“相同手机号”而标为重复。 显式处理
NULL
:
PARTITION BY COALESCE(phone, CONCAT('null_', id))
或用
CASE WHEN phone IS NULL THEN -1 ELSE phone END
字符串字段注意前后空格:
TRIM(phone)
再参与分组 数字型 ID 和字符串型 ID 混用会触发隐式转换,导致分组错乱,务必统一类型(如都转
CAST(id AS VARCHAR)
) 这些细节不报错,但结果偏差隐蔽,上线前一定要用含
NULL
和空值的真实样本验证。

相关文章