SQL SELECT DISTINCT 语句(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在数据查询的世界中,重复数据如同杂草般难以忽视。无论是统计不同类别的商品数量,还是分析用户来源的多样性,开发者都需要一种高效的方法来“筛除”冗余信息。SQL SELECT DISTINCT 语句正是为此而生的工具。它如同一位精准的分类师,能快速识别并保留唯一值,帮助开发者从海量数据中提取核心信息。本文将通过基础概念、语法解析、实际案例及性能优化策略,逐步揭开这一语句的奥秘。
一、理解 SELECT 和 DISTINCT 的基础逻辑
1.1 SELECT 的核心作用
在 SQL 语言中,SELECT
是查询数据的基石。它的核心功能是“从表中选取数据”。例如:
SELECT name, age FROM students;
这条语句会返回 students
表中所有行的 name
和 age
字段。但问题在于,如果表中存在重复值(如多个学生同名),结果会保留所有重复项。
1.2 DISTINCT 的诞生背景
假设我们想统计班级中有多少“不同年龄”的学生,但原始数据中可能有多个同龄人。此时,DISTINCT
就像一个“去重过滤器”,仅保留唯一值:
SELECT DISTINCT age FROM students;
这条语句会返回所有不重复的年龄值,例如 18
, 19
, 20
,而忽略重复的同一年龄记录。
1.3 两者的结合:语法结构
SELECT DISTINCT
的完整语法为:
SELECT DISTINCT column1, column2, ...
FROM table_name
WHERE condition;
其中,DISTINCT
关键字必须紧跟在 SELECT
之后,且可以作用于单列或多列组合。
二、DISTINCT 的核心应用场景
2.1 单列去重:基础用法
场景:统计某电商平台上所有商品的“品牌种类”。
SELECT DISTINCT brand FROM products;
这条语句会列出所有不重复的 brand
值,例如 Nike
, Adidas
, Apple
等。
比喻:
想象你有一堆混杂的水果,DISTINCT 就像将它们按种类分类后,只保留一个代表样本。
2.2 多列去重:组合唯一性
场景:分析用户订单中“不同地区的不同商品类型”的分布。
SELECT DISTINCT region, product_type
FROM orders;
此时,DISTINCT 会同时检查 region
和 product_type
的组合是否唯一。例如,若上海(region
)同时出现过两次“家电”(product_type
),则仅保留一条记录。
关键点:
多列去重时,所有指定列的组合值必须完全相同才会被视作重复。
2.3 结合聚合函数:统计唯一值数量
若想直接获取去重后的记录总数,可与 COUNT()
函数结合:
SELECT COUNT(DISTINCT user_id) AS unique_users
FROM log_table;
这条语句会返回日志表中唯一用户的数量。
三、进阶技巧与常见误区
3.1 DISTINCT 与 WHERE 的配合使用
案例:统计“年龄在 20 岁以上”的不同专业。
SELECT DISTINCT major
FROM students
WHERE age > 20;
注意,DISTINCT
的作用范围仅限于 SELECT
列表中的字段,而 WHERE
子句先过滤数据,再执行去重。
3.2 多列去重的“陷阱”
假设执行以下语句:
SELECT DISTINCT id, name, age
FROM users;
若某条记录的 id
不同,但 name
和 age
相同,它们仍会被视为两条独立记录。因此,DISTINCT 总是基于所有指定列的组合判断重复性。
3.3 性能优化:DISTINCT 的代价
- 索引的重要性:若频繁对大表使用
DISTINCT
,建议为查询列添加索引,以加速排序和去重过程。 - 避免过度使用:若去重列的数据量极大(如
VARCHAR(1000)
字段),可能显著增加内存消耗。
四、实战案例:DISTINCT 在真实场景中的应用
4.1 案例 1:分析用户活跃渠道
目标:统计某应用用户注册时使用的不同渠道(如微信、短信、邮箱)。
CREATE TABLE registrations (
id INT PRIMARY KEY,
channel VARCHAR(50),
timestamp DATETIME
);
INSERT INTO registrations VALUES
(1, '微信', '2023-01-01'),
(2, '短信', '2023-01-02'),
(3, '微信', '2023-01-03');
SELECT DISTINCT channel FROM registrations;
结果:微信
, 短信
。
4.2 案例 2:查找重复订单
目标:找出订单表中同一用户在同一天提交的多个订单。
SELECT user_id, order_date, COUNT(*) AS order_count
FROM orders
GROUP BY user_id, order_date
HAVING COUNT(*) > 1;
虽然此查询未直接使用 DISTINCT
,但其逻辑与去重思想相通。
4.3 案例 3:多列去重的复杂场景
目标:统计某平台不同城市中不同品类的销量冠军。
SELECT DISTINCT city, category, MAX(sales) AS max_sales
FROM sales_data
GROUP BY city, category;
此语句通过分组(GROUP BY
)和聚合函数(MAX
),结合 DISTINCT
确保每组仅保留最高销量记录。
五、常见问题解答
5.1 问题 1:DISTINCT 和 GROUP BY 有什么区别?
- DISTINCT:直接返回唯一值,适用于简单去重。
- GROUP BY:需配合聚合函数(如
COUNT
),用于按组统计信息。
例如,统计不同年龄的人数:
-- 使用 GROUP BY
SELECT age, COUNT(*) FROM students GROUP BY age;
-- 使用 DISTINCT(无法直接统计数量)
SELECT DISTINCT age FROM students;
5.2 问题 2:DISTINCT 是否会影响查询性能?
是的。当数据量较大时,DISTINCT 需要额外的排序和内存资源。可通过以下方式优化:
- 为查询列添加索引。
- 减少返回的列数量(仅选择必要字段)。
5.3 问题 3:能否对计算字段使用 DISTINCT?
可以!例如:
SELECT DISTINCT CONCAT(first_name, ' ', last_name) AS full_name
FROM employees;
此语句会去重全名字段,即使 first_name
或 last_name
单独重复,组合唯一时仍保留。
六、结论
SQL SELECT DISTINCT 语句是开发者工具箱中的核心工具之一,它通过精准的去重能力,帮助我们从复杂数据中提取关键信息。无论是基础的单列去重,还是多列组合的复杂场景,DISTINCT 都能以简洁的语法实现高效操作。
然而,其性能代价也不容忽视。合理设计索引、理解查询逻辑,并结合 GROUP BY
等其他子句,才能最大化其价值。对于开发者而言,掌握这一语句不仅是技术上的提升,更是数据思维的深化——毕竟,数据的价值,往往藏在“去粗取精”的过程中。
希望本文能帮助你更好地理解并运用 SQL SELECT DISTINCT 语句,在实际开发中游刃有余地应对各类数据挑战!