在Oracle数据库的日常查询中,我们经常会遇到结果集包含重复行的情况,比如统计客户分布的城市列表时,同一个城市可能出现几十次。这时DISTINCT关键字就派上了用场,它能够剔除查询结果中的重复记录,只返回唯一的数据行。虽然DISTINCT看起来简单,但很多初学者在使用时容易踩坑,比如误以为DISTINCT只作用于紧跟其后的那一列,或者对NULL值的处理产生疑惑。本文将从基础语法出发,逐步深入讲解DISTINCT的工作原理、典型用法和常见疑问,帮助你彻底掌握这个高频关键字。
DISTINCT的基本语法与工作原理
DISTINCT必须紧跟在SELECT关键字之后,放在第一个列名之前,它的作用范围是SELECT列表中的所有列,而不是单独某一列。这一点是初学者最容易误解的地方。基本语法如下:
SELECT DISTINCT column1, column2, ... FROM table_name;
从底层原理来看,Oracle在执行含DISTINCT的查询时,会对结果集进行排序或哈希操作,把所有列的组合值完全相同的行只保留一条。注意这里的判断标准是整行的列值组合,只要有一列的值不同,就不算重复。Oracle优化器通常会选择SORT UNIQUE或HASH UNIQUE两种操作方式之一来完成去重,数据量较大时一般采用哈希方式以减少排序开销。
需要特别说明的是,DISTINCT会对NULL值做特殊处理。Oracle认为所有NULL彼此相等,因此在去重时,多个NULL只会保留一行。这与我们直觉上认为NULL不等于任何值的理解不同,实际写SQL时要注意这一点。
单列与多列去重的具体用法
单列去重是最常见的场景。例如查询员工表中有哪些部门编号:
SELECT DISTINCT department_id FROM employees ORDER BY department_id;
多列去重时,DISTINCT作用于所有列的组合。例如查询员工表中不重复的部门与职位组合:
SELECT DISTINCT department_id, job_id FROM employees;
这条语句返回的是部门编号和职位编号组合不重复的记录,而不是分别对两列去重。如果你想分别统计,就需要拆成两条独立的查询。另外,DISTINCT也可以和函数结合使用,例如查询不重复的姓氏长度:
SELECT DISTINCT LENGTH(last_name) AS name_len FROM employees;
在使用DISTINCT时还可以配合WHERE条件先过滤再去重,这样能减少参与去重的数据量,提升查询效率。一个良好的习惯是:尽量在FROM和WHERE阶段缩小数据范围,把DISTINCT作为最后一步处理手段。
DISTINCT与GROUP BY的异同对比
很多开发者会疑惑:既然GROUP BY也能实现去重,两者有什么区别?从去重效果上看,下面两条语句返回的结果集相同:
SELECT DISTINCT department_id FROM employees; SELECT department_id FROM employees GROUP BY department_id;
它们的区别主要在于功能扩展性。GROUP BY可以在去重的基础上进行聚合计算,比如统计每个部门的人数:
SELECT department_id, COUNT(*) AS emp_count FROM employees GROUP BY department_id;
而DISTINCT只能返回唯一行,无法附加聚合结果。反过来,如果只需要去重而不需要聚合,DISTINCT语义更直观,可读性更好。从性能角度看,单纯去重时两者的执行计划基本一致,Oracle优化器内部对它们的处理方式相似,不必纠结性能差异,应根据语义选择合适的写法。
还有一种进阶用法是在聚合函数内部使用DISTINCT,例如统计去重后的客户数量:
SELECT COUNT(DISTINCT customer_id) AS customer_count FROM orders;
这种写法统计的是不重复的客户数,而不是订单数,是数据分析中非常实用的技巧。
DISTINCT使用中的常见疑问解答
第一个常见疑问:DISTINCT为什么没有生效?多数情况是SELECT列表中包含了主键或唯一性很高的列,比如不小心把ID列也查了出来,整行自然不会重复。排查方法是逐列检查,去掉不该出现的列。
第二个疑问:DISTINCT和ORDER BY能一起用吗?完全可以,Oracle会先去重再排序,但要注意ORDER BY的列一般应出现在SELECT列表中,否则可能报ORA-01791错误。
第三个疑问:DISTINCT会影响性能吗?会有一定开销,因为去重需要额外的排序或哈希操作,数据量大时应评估必要性,能通过表设计或查询条件避免重复数据时,尽量不用DISTINCT兜底。
第四个疑问:DISTINCT NULL怎么处理?前面已经提到,多个NULL会被视为相同值只保留一条,如果想排除NULL,需要用WHERE条件显式过滤,例如WHERE column IS NOT NULL。掌握这些要点,就能在实际工作中灵活运用DISTINCT,写出准确高效的查询语句。
Oracle DistinctDISTINCT去重Oracle SQL修改时间:2026-08-31 05:12:54