讲解

查询结果里经常包含重复值:学生表里查城市,北京会出现三次。DISTINCT 关键字去掉结果中的重复行:SELECT DISTINCT city FROM students 每个城市只出现一次。它紧跟在 SELECT 后面,作用于整个结果行。

选择多列时,DISTINCT 是对「列的组合」去重:SELECT DISTINCT city, class_name FROM students 会把(城市, 班级)的组合视为一个整体,只有组合完全相同的行才会合并。这是最容易误解的地方——DISTINCT 不是只对它后面那一列生效。

DISTINCT 也常和聚合函数搭配:COUNT(DISTINCT city) 统计有多少个不同的城市。另外要注意 NULL:去重时所有 NULL 被视为彼此相同,结果里最多保留一个 NULL;而 COUNT(DISTINCT 列) 和 COUNT(列) 一样会忽略 NULL,不计入个数。

示例

学生都来自哪些城市(注意结果里包含一个 NULL,表示有学生城市未知):

SELECT DISTINCT city FROM students;

对组合去重:城市与班级的搭配关系:

SELECT DISTINCT city, class_name FROM students;

统计不同城市的个数(NULL 不计入):

SELECT COUNT(DISTINCT city) AS city_count FROM students;

常见坑

  • 以为 DISTINCT 只作用于紧邻的一列:SELECT DISTINCT city, class_name 去重的是两列的组合,不是先对城市去重再随便配个班级。理解成「整行去重」就不会错。
  • 用 DISTINCT 掩盖多表连接的错误:JOIN 写错导致行翻倍,有人图省事加个 DISTINCT「压回去」。这是治标不治本,正确做法是检查连接条件为什么产生了重复。
  • 忽略 NULL 的去重语义:多个 NULL 只保留一个,这通常符合预期,但如果业务上 NULL 代表不同含义(未填写 vs 不适用),去重结果可能掩盖差异。
  • 在大结果集上滥用 DISTINCT:去重要对全部结果排序或建哈希,数据量大时开销不小。先想清楚是否真的需要去重,以及能否用 GROUP BY 表达得更清楚。

小结

DISTINCT 对整个结果行去重,多列时按组合判断,NULL 视为相同且 COUNT(DISTINCT) 忽略 NULL。下一节细看 WHERE 里的比较运算符。