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
五、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使用要点总结
语法要点
性能优化建议
索引优化:对频繁用于DISTINCT查询的列建立索引
减少数据量:先使用WHERE条件过滤,再应用DISTINCT
考虑替代方案:小范围唯一值使用DISTINCT,大数据量分组统计考虑GROUP BY
避免过度使用:不要对所有查询都加DISTINCT,只在需要时使用
常见误区与陷阱
误解NULL处理:多个NULL值会被DISTINCT视为相同,只保留一个
混淆DISTINCT位置:DISTINCT必须紧跟在SELECT之后
不必要的去重:主键或唯一列本身就没有重复,不需要DISTINCT
性能忽视:对大表的多列DISTINCT查询可能很慢

发表评论
所有评论