mysql菜鸟教程
6.4 去重查询:DISTINCT
在实际数据查询中,我们经常需要从重复的数据中提取唯一值。比如查看公司有哪些不同的部门、商品有哪些不同的分类、学生来自哪些不同的城市等。DISTINCT关键字就是SQL中的“数据去重器”,它能从查询结果中消除完全重复的行,只保留唯一的记录。
一、DISTINCT的核心价值与应用场景
为什么要使用DISTINCT?
-
数据清洗:快速查看某个字段有哪些不同的取值
-
统计基数:了解数据列的取值多样性
-
简化报表:生成不重复的下拉列表选项
-
优化查询:在某些场景下减少后续处理的数据量
典型应用场景
-
获取客户所在的所有城市列表
-
查看商品的所有分类目录
-
统计系统中有哪些不同的用户角色
-
生成报表中的维度选择项
二、DISTINCT基础语法
DISTINCT关键字的基本使用方式:
单列去重
SELECT DISTINCT 列名
FROM 表名
[WHERE 条件];
多列组合去重
SELECT DISTINCT 列名1, 列名2, ...
FROM 表名
[WHERE 条件];
继续使用学生信息表,并扩展一些数据:
-- 扩展students表数据,增加更多重复项用于演示
INSERT INTO students (name, gender, age, major, score, enrollment_date) VALUES
('张三', '男', 20, '计算机科学', 85.5, '2024-09-01'),
('李四', '女', 19, '软件工程', 92.0, '2024-09-01'),
('王五', '男', 21, '数据科学', 78.0, '2024-09-01'),
('赵六', '女', 22, '计算机科学', 88.5, '2024-09-01'),
('钱七', '男', 20, '软件工程', 95.0, '2024-09-01'),
('孙八', '女', 19, '人工智能', 59.5, '2024-09-01'),
('周九', '女', 19, '人工智能', 91.5, '2023-09-01'),
('吴十', '男', 21, '计算机科学', 76.0, '2023-09-01');
三、基础用法示例
1. 单字段去重
-- 查看所有不重复的专业
SELECT DISTINCT major
FROM students;
-- 查看所有不重复的年龄
SELECT DISTINCT age
FROM students
WHERE age IS NOT NULL
ORDER BY age;
执行结果示例:
+-----------------+
| major |
+-----------------+
| 计算机科学 |
| 软件工程 |
| 数据科学 |
| NULL |
| 人工智能 |
+-----------------+
2. 多字段组合去重
-- 查看不重复的(性别,年龄)组合
SELECT DISTINCT gender, age
FROM students
WHERE gender IS NOT NULL AND age IS NOT NULL
ORDER BY gender, age;
执行结果示例:
+--------+-----+
| gender | age |
+--------+-----+
| 女 | 19 |
| 女 | 22 |
| 男 | 20 |
| 男 | 21 |
+--------+-----+
3. 结合WHERE条件
-- 查看2024年入学的学生有哪些不同的专业
SELECT DISTINCT major
FROM students
WHERE YEAR(enrollment_date) = 2024
AND major IS NOT NULL
ORDER BY major;
4. 结合ORDER BY排序
-- 按字母顺序查看所有不重复的专业
SELECT DISTINCT major
FROM students
WHERE major IS NOT NULL
ORDER BY major;
-- 查看不重复的专业和对应的学生数量
SELECT DISTINCT major, COUNT(*) AS student_count
FROM students
WHERE major IS NOT NULL
GROUP BY major
ORDER BY student_count DESC;
四、DISTINCT vs GROUP BY:两种去重方式对比
DISTINCT和GROUP BY都可以实现去重效果,但它们在语义和用法上有重要区别:
示例对比
-- 使用DISTINCT:只关心不同的值本身
SELECT DISTINCT major
FROM students
WHERE major IS NOT NULL;
-- 使用GROUP BY:分组后可以计算聚合信息
SELECT major, COUNT(*) AS student_count
FROM students
WHERE major IS NOT NULL
GROUP BY major;
关键区别总结
特性
DISTINCT
GROUP BY
主要目的
消除重复行,获取唯一值
按指定列分组,通常用于聚合计算
聚合函数
不能直接与聚合函数一起作用于其他列
可以
与聚合函数(COUNT、SUM等)一起使用
语义重点
"有哪些不同的值"
"按某个维度分组统计"
性能表现
通常稍微高效一些(如果只需去重)
功能更强大,可能稍微复杂
结果排序
不保证结果顺序(除非用ORDER BY)
某些数据库默认按分组列排序
实际选择建议
-
如果只需要获取不重复的值列表 → 使用DISTINCT
-
如果需要对分组进行统计计算 → 使用GROUP BY
五、DISTINCT使用注意事项
1. NULL值的处理
-- DISTINCT将多个NULL值视为相同的,只返回一个NULL
SELECT DISTINCT major FROM students;
-- 如果有多行major为NULL,结果中只显示一个NULL
2. 性能考虑
-
DISTINCT需要对结果集进行排序和去重操作,可能影响查询性能
-
对大数据表使用DISTINCT时要注意效率
-
如果经常需要某个字段的去重值,考虑建立索引
3. 与聚合函数的使用
-- DISTINCT可以与聚合函数结合,对计算前的值去重
SELECT COUNT(DISTINCT major) AS unique_majors
FROM students;
-- 统计有多少个不同的专业(NULL不计数)
SELECT AVG(DISTINCT score) AS avg_unique_score
FROM students
WHERE score IS NOT NULL;
-- 计算不同分数值的平均值(重复分数只计一次)
六、实用技巧与高级用法
1. 多级去重统计
-- 统计每个专业有多少个不同的年龄
SELECT
major,
COUNT(DISTINCT age) AS distinct_ages_count
FROM students
WHERE major IS NOT NULL AND age IS NOT NULL
GROUP BY major;
2. 与其他子句组合的完整查询
-- 复杂的去重查询示例
SELECT DISTINCT
major,
FLOOR(age/10)*10 AS age_group -- 按10岁分组:10-19, 20-29等
FROM students
WHERE major IS NOT NULL
AND age IS NOT NULL
AND score > 60
AND enrollment_date >= '2023-01-01'
ORDER BY major, age_group;
3. 在子查询中使用DISTINCT
-- 先获取不重复的专业,再查询每个专业的详细信息
SELECT *
FROM students
WHERE major IN (
SELECT DISTINCT major
FROM students
WHERE major IS NOT NULL
)
ORDER BY major, score DESC;
4. 使用DISTINCT ON(非MySQL语法,了解即可)
-- PostgreSQL的DISTINCT ON语法(MySQL不支持)
-- 获取每个专业的最高分学生(MySQL需用其他方式实现)
-- PostgreSQL: SELECT DISTINCT ON (major) * FROM students ORDER BY major, score DESC;
七、实战练习与解答
练习题目
基于students表,请编写SQL语句实现以下需求:
-
基础练习:查看所有不重复的学生年龄
-
条件去重:查看2024年入学的学生来自哪些不同的专业
-
多列去重:查看不重复的(专业,性别)组合
-
统计去重:统计学校共有多少个不同的专业
-
综合应用:查看每个专业不重复的年龄数量,并按数量降序排列
-
挑战题:找出有多个学生同名的专业
参考答案
-- 1. 查看所有不重复的学生年龄
SELECT DISTINCT age
FROM students
WHERE age IS NOT NULL
ORDER BY age;
-- 2. 查看2024年入学的学生来自哪些不同的专业
SELECT DISTINCT major
FROM students
WHERE YEAR(enrollment_date) = 2024
AND major IS NOT NULL
ORDER BY major;
-- 3. 查看不重复的(专业,性别)组合
SELECT DISTINCT major, gender
FROM students
WHERE major IS NOT NULL AND gender IS NOT NULL
ORDER BY major, gender;
-- 4. 统计学校共有多少个不同的专业
SELECT COUNT(DISTINCT major) AS unique_major_count
FROM students;
-- 5. 查看每个专业不重复的年龄数量,按数量降序排列
SELECT
major,
COUNT(DISTINCT age) AS unique_age_count
FROM students
WHERE major IS NOT NULL AND age IS NOT NULL
GROUP BY major
ORDER BY unique_age_count DESC;
-- 6. 找出有多个学生同名的专业
SELECT major, name, COUNT(*) as name_count
FROM students
WHERE major IS NOT NULL
GROUP BY major, name
HAVING COUNT(*) > 1;
八、DISTINCT使用要点总结
语法要点
语法形式
说明
示例
单列去重
SELECT DISTINCT column
SELECT DISTINCT major
多列去重
SELECT DISTINCT col1, col2
SELECT DISTINCT major, gender
与聚合函数
COUNT(DISTINCT column)
COUNT(DISTINCT major)
结合WHERE
先筛选后去重
WHERE score > 60
结合ORDER BY
去重后排序
ORDER BY major ASC
性能优化建议
-
索引优化:对频繁用于DISTINCT查询的列建立索引
-
减少数据量:先使用WHERE条件过滤,再应用DISTINCT
-
考虑替代方案:小范围唯一值使用DISTINCT,大数据量分组统计考虑GROUP BY
-
避免过度使用:不要对所有查询都加DISTINCT,只在需要时使用
常见误区与陷阱
-
误解NULL处理:多个NULL值会被DISTINCT视为相同,只保留一个
-
混淆DISTINCT位置:DISTINCT必须紧跟在SELECT之后
-
不必要的去重:主键或唯一列本身就没有重复,不需要DISTINCT
-
性能忽视:对大表的多列DISTINCT查询可能很慢

发表评论
所有评论