SQL去重查询怎么实现_真实案例解析强化复杂查询思维【教学】

SQL去重需按业务需求选择方法:纯值去重用DISTINCT,按维度取最新记录用ROW_NUMBER()窗口函数,合并多行数据用GROUP BY配合STRING_AGG等聚合函数。

SQL去重不是简单加个 DISTINCT 就完事——它得看你要去重的维度、是否保留其他字段、要不要最新/最全记录,甚至还要考虑性能和业务逻辑。下面用几个真实场景讲清楚怎么选对方法。

基础去重:只取唯一值,不关心哪一条

最常见需求:查出所有不重复的部门名称、城市、产品类别等。

  • 直接用 SELECT DISTINCT 列名,简单高效
  • 注意:DISTINCT 作用于整行结果,如果 SELECT 多列,只要组合值相同就会被去重
  • 错误示范:SELECT DISTINCT dept_name, hire_date FROM emp —— 可能返回同一部门多条记录(因入职时间不同),这不是你想要的“按部门去重”

按某列去重,但要保留完整信息(比如每部门最新一条员工)

这时候 DISTINCT 不够用了,得靠窗口函数或关联子查询。

  • 推荐用 ROW_NUMBER() OVER (PARTITION BY 部门 ORDER BY 入职日期 DESC) 标序号,再外层筛选 rn = 1
  • 示例:SELECT * FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY updated_at DESC) AS rn FROM employees) t WHERE t.rn = 1
  • 替代方案:用 GROUP BY + 聚合函数(如 MAX(id)),再连表查原记录——适合主键明确、逻辑清晰的场景

去重同时要统计或合并数据(如合并同一用户的多条标签)

不是删记录,而是把重复维度下的多行聚合成一行。

  • GROUP BY + STRING_AGG(PostgreSQL)、GROUP_CONCAT(MySQL)、STRING_AGG(SQL Server 2017+)
  • 例如:把用户所有兴趣标签拼成逗号分隔字符串:SELECT user_id, STRING_AGG(interest, ', ') FROM user_interests GROUP BY user_id
  • 注意 NULL 处理和去重嵌套(如先 DISTINCT 再聚合):部分数据库支持 STRING_AGG(DISTINCT interest, ', ')

误删风险高?先验证,再操作

真正删数据前,务必确认哪些行会被影响。

  • 先运行 SELECT COUNT(*) 和 COUNT(DISTINCT xxx) 对比,看重复比例
  • GROUP BY + HAVING COUNT(*) > 1 查出具体重复组:SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1
  • 删数据别直接 DELETE FROM table;建议用临时表存要保留的ID,或加事务 + LIMIT 测试

基本上就这些。去重本质是明确“以什么为单位算重复”,再匹配工具:纯值用 DISTINCT,带逻辑用窗口函数,要聚合用 GROUP BY。别硬套模板,先想清楚业务含义。