几种去重的SQL写法

在 SQL 中,数据去重有多种实现方式,以下是几种常见写法及其适用场景:

1. 使用 DISTINCT 关键字

语法:
SELECT DISTINCT column1 [, column2, ...]  
FROM table_name;  

说明:直接对指定字段组合进行唯一性筛选,仅保留首次出现的记录。
示例:
SELECT DISTINCT address FROM student; -- 获取不重复的地址  

局限性:
  • 若对多字段去重,需所有字段值完全相同才视为重复。
  • 无法同时返回非去重字段的原始值,仅能展示去重字段。

2. 使用 GROUP BY 子句

语法:
SELECT column1 [, aggregate_function(column2), ...]  
FROM table_name  
GROUP BY column1 [, column2, ...];  

说明:按指定字段分组,结合聚合函数(如 MAXMINCOUNT 等)获取其他字段信息。
示例:
SELECT MIN(id), address FROM student GROUP BY address; -- 按地址去重,返回每组最小 id  

注意:非聚合字段可能来自不同记录,导致数据逻辑上不一致(如不同 id 对应同一 address 时,聚合函数外的字段取值无明确规律)。

3. 使用窗口函数(如 ROW_NUMBER()

语法:
SELECT *  
FROM (  
    SELECT *, ROW_NUMBER() OVER (PARTITION BY column1 ORDER BY column2) AS rn  
    FROM table_name  
) AS t  
WHERE rn = 1;  

说明:先按 PARTITION BY 分组,再按 ORDER BY 排序并生成行号,筛选行号为 1 的记录。
示例:
SELECT id, name, address  
FROM (  
    SELECT *, ROW_NUMBER() OVER (PARTITION BY address ORDER BY id ASC) AS rn  
    FROM student  
) AS a  
WHERE a.rn = 1; -- 按地址去重,保留每组 id 最小的记录  

优势:可精准控制保留哪条记录(如按时间、ID 排序取最新或最旧),但低版本 MySQL 不支持窗口函数。

4. 使用 IN 子查询

语法:
SELECT *  
FROM table_name  
WHERE id IN (SELECT MAX(id) FROM table_name GROUP BY column1);  

说明:通过子查询找到每组唯一标识字段(如自增 id)的最大值,再筛选主表中对应记录。
示例:
SELECT * FROM student WHERE id IN (SELECT MAX(id) FROM student GROUP BY address); -- 按地址去重,取每组最大 id 的记录  

适用场景:表中存在唯一标识字段(如 id),且需保留特定条件(如最大 / 最小 id)的记录。

5. 使用 NOT EXISTS

语法:
 
SELECT a.*  
FROM table_name a  
WHERE NOT EXISTS (  
    SELECT 1 FROM table_name b  
    WHERE a.column1 = b.column1 AND a.id < b.id  
);  

示例:
SELECT a.* FROM student a WHERE NOT EXISTS (SELECT 1 FROM student b WHERE a.address = b.address AND a.id < b.id); -- 按地址去重,保留每组 id 最大的记录  

逻辑:对于每一行 a,若不存在 b 行(同 column1 且 id 更大),则保留 a

6. 使用 UNION 去重

语法:
SELECT column1 [, column2, ...]  
FROM table_name1  
UNION  
SELECT column1 [, column2, ...]  
FROM table_name2;  

说明:合并多个查询结果并自动去重(UNION ALL 保留全部记录,不进行去重)。
示例:
SELECT address FROM student UNION SELECT address FROM teacher; -- 合并两表地址并去重  

注意:大数据量时效率较低,建议先用 UNION ALL 再结合其他方法去重。

7. 使用 INNER JOIN + GROUP BY

语法:
SELECT a.*  
FROM table_name a  
INNER JOIN (  
    SELECT column1, MAX(id) AS max_id  
    FROM table_name  
    GROUP BY column1  
) b ON a.column1 = b.column1 AND a.id = b.max_id;  

示例:
 
SELECT a.* FROM student a  
INNER JOIN (SELECT address, MAX(id) AS max_id FROM student GROUP BY address) b  
ON a.address = b.address AND a.id = b.max_id; -- 按地址去重,取每组最大 id 的记录  
逻辑:先通过子查询获取每组最大 id,再与主表关联筛选。

实际应用中,可根据数据库特性(如是否支持窗口函数)、数据规模、业务需求(如保留特定记录)选择合适的方法。例如,简单单字段去重优先用 DISTINCT;需保留其他字段且数据一致性要求不高时用 GROUP BY;需精准控制保留记录时用窗口函数或 IN/NOT EXISTS 等。

posted on 2025-06-06 15:55  数据派  阅读(529)  评论(0)    收藏  举报