SQL Server中去重只取一条记录的常用方法
在使用SQL Server数据库时,经常需要处理包含重复字段的数据表,要求根据某些列进行分组后,仅返回每条分组中的一条记录。本文将介绍几种实现该需求的SQL查询方法,涵盖基于聚合函数的基础筛选以及更灵活的窗口函数应用。
问题场景与需求
假设我们有一张测试数据表 TestData,其中包含主键 ID 以及其他业务字段如 Data、ColA 等。当 Data 字段存在大量重复值时,我们需要从表中提取出每个 Data 值对应的一条完整记录(通常是最早录入的那条,即ID最小的那一条)。
方法一:使用 GROUP BY 与子查询
这是最直观且兼容性良好的方法。其核心逻辑是先找出每个分组中的最小 ID,然后在主查询中筛选出这些 ID 对应的所有字段。
第1步:建立数据表与插入测试数据
首先,我们需要构建一个示例环境,包含必要的结构和测试数据。
-- 建立数据表
CREATE TABLE TestData (
ID int identity(1,1) primary key,
Data int,
ColA varchar(20),
ColB varchar(20)
);
GO
-- 插入测试数据 (模拟批量导入)
DECLARE @counts int;
DECLARE @i int;
SET @counts = 1000;
SET @i = 1;
WHILE @i <= @counts
BEGIN
INSERT TestData (Data, ColA, ColB)
VALUES
(CAST(RAND() * 10000 AS INT),
CAST(RAND() AS VARCHAR(20)),
CAST(RAND() AS VARCHAR(20)));
SET @i = @i + 1;
END;
第2步:编写去重查询语句
利用子查询获取每个 Data 组的最小 ID,并通过 IN 条件过滤主表数据。
-- 获取数据:根据Data分类,只取ID最小的一条
SELECT *
FROM TestData
WHERE ID IN (
-- 根据Data分类获取数据最小ID列表
SELECT MIN(ID)
FROM TestData
GROUP BY Data
);
结果说明: 执行上述查询后,返回的结果集中,每个不同的 Data 值仅出现一次,且为该值首次插入时生成的记录(ID最小)。
方法二:使用 ROW_NUMBER() 窗口函数(推荐)
虽然方法一简单有效,但如果需要根据除主键外的其他条件(如更新时间最新、某个分数最高)来选择“唯一”记录,ROW_NUMBER() 是更强大的工具。它允许我们在分组内对行进行编号。
第1步:使用CTE进行编号
创建一个公用表表达式(CTE),按 Data 分组,并在组内按 ID 升序排列,赋予行号。
WITH RankedData AS (
SELECT
ID,
Data,
ColA,
ColB,
ROW_NUMBER() OVER(PARTITION BY Data ORDER BY ID ASC) as rn
FROM TestData
)
第2步:筛选行号为1的记录
从 CTE 中选择行号 rn = 1 的记录,即为每组的第一条数据。
SELECT ID, Data, ColA, ColB
FROM RankedData
WHERE rn = 1;
优势: 此方法无需关联或子查询IN操作,通常在大数据量下性能更优,且灵活性极高,只需修改 ORDER BY 子句即可改变选取规则(例如改为 ORDER BY CreateDate DESC 获取最新记录)。
注意事项与排错
- 数据一致性: 确保用于分组的字段(如
Data)确实是你希望视为“重复”的业务键。如果多个字段共同决定重复性,需在GROUP BY或PARTITION BY中同时列出这些字段。 - 性能优化: 对于大表,建议在参与分组和排序的列上创建索引。例如,为
TestData表的Data列创建索引可以加速GROUP BY或窗口函数的执行。 - NULL值处理:
GROUP BY会将NULL视为一个独立的组。如果需要排除 NULL 值,请在 WHERE 子句中添加额外判断。
以上就是SQL Server中处理重复数据只取一条的详细内容,更多关于SQL Server查询优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













