mysql菜鸟教程

首页 >> mysql菜鸟教程

6.4 去重查询:DISTINCT

      在实际数据查询中,我们经常需要从重复的数据中提取唯一值。比如查看公司有哪些不同的部门、商品有哪些不同的分类、学生来自哪些不同的城市等。DISTINCT关键字就是SQL中的“数据去重器”,它能从查询结果中消除完全重复的行,只保留唯一的记录。

一、DISTINCT的核心价值与应用场景

为什么要使用DISTINCT?

  1. 数据清洗:快速查看某个字段有哪些不同的取值

  2. 统计基数:了解数据列的取值多样性

  3. 简化报表:生成不重复的下拉列表选项

  4. 优化查询:在某些场景下减少后续处理的数据量

典型应用场景

  • 获取客户所在的所有城市列表

  • 查看商品的所有分类目录

  • 统计系统中有哪些不同的用户角色

  • 生成报表中的维度选择项

二、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:两种去重方式对比

DISTINCTGROUP 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语句实现以下需求:

  1. 基础练习:查看所有不重复的学生年龄

  2. 条件去重:查看2024年入学的学生来自哪些不同的专业

  3. 多列去重:查看不重复的(专业,性别)组合

  4. 统计去重:统计学校共有多少个不同的专业

  5. 综合应用:查看每个专业不重复的年龄数量,并按数量降序排列

  6. 挑战题:找出有多个学生同名的专业

参考答案

-- 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

性能优化建议

  1. 索引优化:对频繁用于DISTINCT查询的列建立索引

  2. 减少数据量:先使用WHERE条件过滤,再应用DISTINCT

  3. 考虑替代方案:小范围唯一值使用DISTINCT,大数据量分组统计考虑GROUP BY

  4. 避免过度使用:不要对所有查询都加DISTINCT,只在需要时使用

常见误区与陷阱

  1. 误解NULL处理:多个NULL值会被DISTINCT视为相同,只保留一个

  2. 混淆DISTINCT位置:DISTINCT必须紧跟在SELECT之后

  3. 不必要的去重:主键或唯一列本身就没有重复,不需要DISTINCT

  4. 性能忽视:对大表的多列DISTINCT查询可能很慢


发表评论

昵称:
联系方式:
评论内容:

所有评论

关于我 备案号:蜀ICP备2023042032号-1