SQL子查询中DISTINCT为什么仍有重复数据

千墨姑娘_6047

千墨姑娘_6047

2026-08-19

258人浏览

原创

DISTINCT仅作用于子查询自身结果,JOIN后重复源于关联字段不唯一或条件未收敛;其去重基于整行逐字节比对,非业务逻辑判断;含聚合或窗口函数时冗余甚至报错;ORDER BY字段须在SELECT列表中,否则引发错误或顺序异常。

sql子查询中distinct为什么仍有重复数据

子查询里加了DISTINCT,外层JOIN后还是重复

根本不是DISTINCT没生效,而是它只作用于子查询自身结果——一旦这个“去重后”的结果被用作派生表参与JOIN,而关联字段(比如user_id)在主表中本身就不唯一,或JOIN条件没收敛,就会立刻产生笛卡尔积式膨胀。例如:SELECT * FROM orders o JOIN (SELECT DISTINCT user_id, region FROM users) u ON o.user_id = u.user_id,如果orders里一个user_id对应多条订单,那每条都会和u里该user_id的行匹配,重复就出来了。

  • 先用SELECT *查出原始JOIN结果,看哪几列在变——常是时间戳、明细ID、状态变更记录这类天然不唯一的字段
  • 若只需主表数据,别JOIN子查询,改用EXISTS或IN:把JOIN (SELECT DISTINCT ...)换成WHERE EXISTS (SELECT 1 FROM users u WHERE u.user_id = o.user_id AND u.status = 'active')
  • DISTINCT必须写在子查询最内层SELECT开头,不能只在外层套一层SELECT DISTINCT *,否则只是对已膨胀的结果“事后补救”,性能差还掩盖问题

DISTINCT去不掉“看起来一样”的行

DISTINCT判断重复是逐字节比对整行所有字段值,不是按业务理解“算重复”。两行name相同但created_at差1毫秒、或lotno末尾多了个空格、或一个是NULL一个是空字符串'',全都被视为不同行。

  • 检查重复行的差异字段:用SELECT HEX(col)或LENGTH(col)确认是否有隐藏空格、不可见字符
  • 对字符串字段预处理:TRIM(LOWER(name))、COALESCE(status, 'UNKNOWN'),避免NULL和空值混用
  • MySQL默认不区分大小写,PostgreSQL区分——跨库迁移时DISTINCT行为可能突变

子查询含聚合或窗口函数时DISTINCT冗余甚至报错

当子查询已经用了GROUP BY或ROW_NUMBER(),再加DISTINCT不仅多余,还可能破坏逻辑或触发语法错误。比如SELECT DISTINCT user_id, MAX(create_time) FROM orders GROUP BY user_id,GROUP BY本身已保证user_id唯一,DISTINCT纯属干扰;而SELECT DISTINCT *, ROW_NUMBER() OVER (...) FROM t在多数数据库直接报错,因窗口函数要求明确的排序依据,DISTINCT会打乱行序。

  • 先确认子查询语义是否已隐含唯一性:GROUP BY主键、ROW_NUMBER() ... WHERE rn = 1等场景下删掉DISTINCT
  • 需要“按某列去重并保留完整行”时,DISTINCT完全无能为力,必须用ROW_NUMBER() + CTE或子查询过滤
  • 别在WHERE子句里嵌套窗口函数——ROW_NUMBER()只能出现在CTE、派生表或SELECT列表中

ORDER BY字段不在SELECT列表中导致DISTINCT失效错觉

很多人写SELECT DISTINCT name FROM users ORDER BY created_at,发现结果顺序不对甚至报错,误以为DISTINCT失效。其实是ORDER BY引用了未选字段,数据库要么拒绝执行(如MySQL 5.7+严格模式),要么按内部顺序返回,看起来像“没去重”。

  • ORDER BY字段必须出现在SELECT列表中,或为其定义别名后引用
  • 想按未选字段排序,得改写成子查询:SELECT name FROM (SELECT DISTINCT name, MAX(created_at) AS max_time FROM users GROUP BY name) t ORDER BY max_time
  • PostgreSQL支持DISTINCT ON (col),但MySQL/SQL Server不兼容,线上别依赖

真正麻烦的从来不是DISTINCT写没写,而是你没想清楚:这行重复,到底是数据本身冗余、JOIN路径发散、字段组合天然不唯一,还是业务上根本就需要“留最新那一行”——这时候DISTINCT连入场券都没有。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4843

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

991

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1269

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6881

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3563

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6860

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

9541

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1290

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1132

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习