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 表中所有行的 nameage 字段。但问题在于,如果表中存在重复值(如多个学生同名),结果会保留所有重复项。

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 会同时检查 regionproduct_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 不同,但 nameage 相同,它们仍会被视为两条独立记录。因此,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 需要额外的排序和内存资源。可通过以下方式优化:

  1. 为查询列添加索引。
  2. 减少返回的列数量(仅选择必要字段)。

5.3 问题 3:能否对计算字段使用 DISTINCT?

可以!例如:

SELECT DISTINCT CONCAT(first_name, ' ', last_name) AS full_name  
FROM employees;  

此语句会去重全名字段,即使 first_namelast_name 单独重复,组合唯一时仍保留。


六、结论

SQL SELECT DISTINCT 语句是开发者工具箱中的核心工具之一,它通过精准的去重能力,帮助我们从复杂数据中提取关键信息。无论是基础的单列去重,还是多列组合的复杂场景,DISTINCT 都能以简洁的语法实现高效操作。

然而,其性能代价也不容忽视。合理设计索引、理解查询逻辑,并结合 GROUP BY 等其他子句,才能最大化其价值。对于开发者而言,掌握这一语句不仅是技术上的提升,更是数据思维的深化——毕竟,数据的价值,往往藏在“去粗取精”的过程中。

希望本文能帮助你更好地理解并运用 SQL SELECT DISTINCT 语句,在实际开发中游刃有余地应对各类数据挑战!

最新发布