在数据库日常开发中,判断表中记录是否为重复项是非常常见的需求,比如用户表中同手机号的多条记录、订单表中同订单号的多条异常数据等,都需要我们快速识别并标记重复状态。使用ROW_NUMBER窗口函数可以高效完成这个任务,它能在不改变原表数据的前提下,按指定规则对记录排序编号,通过编号值就能直接判断记录是否重复。

ROW_NUMBER函数基础语法
ROW_NUMBER是SQL标准中的窗口函数,作用是对查询结果集的每一行分配一个唯一的连续整数,编号从1开始。它的基础语法如下:
-- 基础语法
ROW_NUMBER() OVER (
PARTITION BY 分组字段1, 分组字段2... -- 可选,用于指定分组的列,相同值的记录分为一组
ORDER BY 排序字段1 [ASC|DESC], 排序字段2 [ASC|DESC]... -- 必选,用于指定组内排序的规则
) AS 编号别名
其中PARTITION BY子句是可选的,如果不指定则对整个结果集进行编号;ORDER BY子句是必选的,用于指定编号的排序依据。同一个分组内,排序靠前的记录编号更小,编号相同的记录不存在,每行编号都是唯一的。
单字段重复项判断与标记
我们先来看最简单的单字段重复判断场景,比如有一张用户表user_info,结构如下:
-- 用户表结构
CREATE TABLE user_info (
id INT PRIMARY KEY,
user_name VARCHAR(50),
phone VARCHAR(20),
register_time DATETIME
);
现在需要判断phone字段是否存在重复,重复的记录标记为1,非重复的标记为0。我们可以先按phone分组,按register_time升序排序,给每个手机号对应的记录编号,编号为1的是该手机号的第一条记录,编号大于1的就是重复记录。
-- 单字段重复项标记
SELECT
id,
user_name,
phone,
register_time,
ROW_NUMBER() OVER (PARTITION BY phone ORDER BY register_time ASC) AS rn,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY phone ORDER BY register_time ASC) = 1 THEN 0
ELSE 1
END AS is_duplicate
FROM user_info;
执行上面的查询后,is_duplicate字段为0的是该手机号的首条记录,为1的就是重复记录。如果只需要查询所有重复的记录,可以嵌套一层查询筛选rn > 1的记录:
-- 查询所有重复记录
SELECT * FROM (
SELECT
id,
user_name,
phone,
register_time,
ROW_NUMBER() OVER (PARTITION BY phone ORDER BY register_time ASC) AS rn
FROM user_info
) t WHERE t.rn > 1;
多字段重复项判断与标记
实际业务中更多是多字段组合重复的场景,比如订单表中,同一个用户同一个商品在同一天的下单记录视为重复。假设订单表order_info结构如下:
-- 订单表结构
CREATE TABLE order_info (
order_id INT PRIMARY KEY,
user_id INT,
goods_id INT,
order_date DATE,
amount DECIMAL(10,2)
);
现在需要判断user_id、goods_id、order_date三个字段组合是否重复,同样使用ROW_NUMBER,在PARTITION BY后面加上多个分组字段即可:
-- 多字段重复项标记
SELECT
order_id,
user_id,
goods_id,
order_date,
amount,
ROW_NUMBER() OVER (
PARTITION BY user_id, goods_id, order_date
ORDER BY order_id ASC
) AS rn,
CASE
WHEN ROW_NUMBER() OVER (
PARTITION BY user_id, goods_id, order_date
ORDER BY order_id ASC
) = 1 THEN 0
ELSE 1
END AS is_duplicate
FROM order_info;
这里按user_id、goods_id、order_date三个字段分组,同一个用户同一个商品同一天的订单会被分到同一组,按order_id升序排序后,第一条记录编号为1,其余为重复项。
不同数据库的使用注意事项
ROW_NUMBER是SQL标准的窗口函数,大部分主流数据库都支持,但部分细节有差异:
- MySQL从8.0版本开始支持窗口函数,低于8.0的版本无法使用ROW_NUMBER,需要改用变量模拟实现。
- SQL Server、PostgreSQL、Oracle均原生支持ROW_NUMBER函数,语法基本一致。
- 如果需要在分组内按自定义规则排序,比如NULL值排最后,可以在
ORDER BY子句中使用CASE表达式调整排序逻辑。
总结
使用ROW_NUMBER函数判断重复项的核心逻辑是:按重复判断的字段分组,按业务需要的规则排序,给组内记录编号,编号为1的是首条记录,编号大于1的就是重复项。这种方式不需要修改原表结构,查询灵活,支持单字段和多字段的重复判断,是处理重复项标记的高效方案。开发者可以根据实际业务的分组、排序需求调整PARTITION BY和ORDER BY子句,快速适配不同的重复项判断场景。
SQLROW_NUMBER重复项判断窗口函数修改时间:2026-06-13 21:54:21