SQL入门:GROUPBY与DISTINCT-数据分组与去重全解析

GROUP BY可以理解为 “按某个规则把数据分成小组,再对每个小组做汇总”—— 比如把 “所有订单按顾客分组”,统计每个顾客的总消费;而DISTINCT是 “直接去掉重复数据,只保留唯一值”。下面从基础用法到深层对比,带你彻底搞懂两者的区别和适用场景。

一、GROUP BY 的基础概念与作用

1. GROUP BY 的核心作用

GROUP BY的字面意思是 “按... 分组”,功能是:将表中的数据按指定字段(或字段组合)的取值分成多个 “组”,同一组内的字段取值完全相同,然后对每个组单独使用聚合函数(如COUNTSUMAVG等)进行汇总计算。

核心逻辑:“先分组,后聚合”

2. 基础语法结构

SELECT 分组字段, 聚合函数(字段) AS 别名
FROM 表名
[WHERE 筛选条件]  -- 分组前筛选原始数据
GROUP BY 分组字段
[HAVING 聚合条件]; -- 分组后筛选汇总结果

3. 用实例理解:分组 + 聚合

还是用 “订单表(orders)” 为例,表中数据如下:

order_iduser_id(顾客编号)amount(金额)create_time(下单时间)
1101502025-05-01
21021502025-05-01
3101802025-05-02
41032002025-05-02
51021202025-05-03
实例 1:按 “顾客编号(user_id)” 分组,统计每个顾客的订单数和总消费

需求:想知道每个顾客下了多少笔订单,一共花了多少钱。

SELECT 
  user_id AS 顾客编号,  -- 分组字段
  COUNT(*) AS 订单总数, -- 聚合函数:统计每个小组的订单数
  SUM(amount) AS 总消费  -- 聚合函数:计算每个小组的总金额
FROM orders
GROUP BY user_id; -- 按顾客编号分组
  • 分组过程:把user_id相同的记录归为一组(101 一组、102 一组、103 一组);
  • 聚合计算:对每个组算 “订单数” 和 “总消费”;
  • 最终结果:
顾客编号订单总数总消费
1012130 |(订单 1+3:50+80)
1022270 |(订单 2+5:150+120)
1031200 |(订单 4)
实例 2:按 “日期(create_time)” 分组,筛选并统计每天的有效订单

需求:只看 5 月 2 日及之后的订单,按日期分组统计 “金额≥100 的订单数”。

SELECT 
  create_time AS 下单日期,
  COUNT(CASE WHEN amount >= 100 THEN 1 END) AS 大额订单数 -- 条件聚合
FROM orders
WHERE create_time >= '2025-05-02' -- 分组前筛选:只留5.2及之后的订单
GROUP BY create_time
HAVING 大额订单数 > 0; -- 分组后筛选:只留大额订单数>0的日期

结果:

下单日期大额订单数
2025-05-021 |(订单 4 金额 200≥100)
2025-05-031 |(订单 5 金额 120≥100)

4. GROUP BY 的关键规则(小白必记)

  1. 分组字段要完整:如果按多个字段分组(比如 “日期 + 顾客”),GROUP BY后要写所有分组字段,SELECT也要对应。例:按 “日期 + 顾客” 分组,统计每天每个顾客的订单数:
SELECT create_time, user_id, COUNT(*) AS 当日订单数
FROM orders
GROUP BY create_time, user_id; -- 两个分组字段都要写
  1. WHERE 和 HAVING 的区别WHERE管 “分组前”(筛选原始数据),HAVING管 “分组后”(筛选汇总结果),HAVING可以用聚合函数,WHERE不能。
  2. NULL 的处理:分组字段为 NULL 的记录会被归为 “同一个小组”(比如多个user_id为 NULL 的记录,会分成一组)。

二、GROUP BY 与 DISTINCT 的去重对比

DISTINCT的作用是 “去掉重复记录,只保留所有字段都相同的唯一记录”,核心是 “单纯去重,不做汇总”。很多小白会混淆两者,下面从 “功能、用法、场景” 三个维度对比:

1. 核心区别:“去重 + 汇总” vs “单纯去重”

对比维度GROUP BYDISTINCT
核心功能先分组,再对每组做聚合计算(统计、求和等)直接去掉完全重复的记录,只保留唯一值
是否依赖聚合函数必须配合聚合函数(否则意义不大)不依赖任何函数,单独使用
结果含义每个小组的汇总效果(如“每个顾客的总消费”)去重后的原始记录(如“所有不重复的顾客编号”)
执行逻辑分组->聚合计算扫描记录->去重->返回唯一值

2. 实例对比:同样是 “获取不重复的顾客编号”

用 DISTINCT 实现(单纯去重)

需求:只想知道 “有哪些顾客下过单”(不需要统计订单数)。

SELECT DISTINCT user_id AS 不重复顾客编号
FROM orders;
  • 结果(只保留唯一的user_id): 
不重复顾客编号
101
102
103
  • 逻辑:扫描所有user_id,去掉重复的,直接返回唯一值。
用 GROUP BY 实现(分组 + 无意义聚合)

如果硬要用GROUP BY实现 “去重顾客编号”,需要配合无实际意义的聚合函数(比如COUNT(*),但结果会多一列无关的统计值):

SELECT user_id AS 不重复顾客编号, COUNT(*) AS 订单数 -- 必须加聚合函数
FROM orders
GROUP BY user_id;
  • 结果(比 DISTINCT 多了 “订单数” 列):
不重复顾客编号订单数
1012
1022
1031
  • 问题:如果只需要 “不重复的顾客编号”,用GROUP BY会多做一次聚合计算,效率低且结果冗余。

3. 实例对比:“统计不重复顾客数”

用 DISTINCT+COUNT 实现

需求:想知道 “一共有多少个不同的顾客下过单”。

SELECT COUNT(DISTINCT user_id) AS 不重复顾客总数
FROM orders;
  • 结果:不重复顾客总数 = 3(直接统计去重后的user_id数量)。
用 GROUP BY+COUNT 实现

先按user_id分组,再统计 “小组的数量”(需要嵌套子查询):

SELECT COUNT(*) AS 不重复顾客总数
FROM (
  -- 子查询:按user_id分组,得到每个小组的user_id
  SELECT user_id
  FROM orders
  GROUP BY user_id
) AS 分组结果;
  • 结果同样是3,但逻辑更复杂:先分组得到 3 个小组,再统计小组数量。
  • 问题:比DISTINCT+COUNT多了一层子查询,执行效率更低,代码更繁琐。

4. 什么时候用 GROUP BY?什么时候用 DISTINCT?

优先用 DISTINCT 的场景
  • 只需要 “去掉重复记录”,不需要任何汇总计算(如 “获取所有不重复的商品分类”“获取所有不重复的下单日期”);
  • 统计 “不重复值的数量”(如 “统计不重复的顾客数”“统计不重复的订单日期数”),用COUNT(DISTINCT 字段)更简洁。
必须用 GROUP BY 的场景
  • 需要 “按分组做汇总计算”(如 “每个顾客的总消费”“每天的订单总数”“每个商品分类的平均价格”);
  • 需要 “分组后筛选汇总结果”(如 “总消费超过 100 元的顾客”“订单数超过 1 笔的日期”),必须用GROUP BY+HAVING

5. 性能对比:谁更快?

  • 当只需要 “单纯去重” 或 “统计不重复值数量” 时:DISTINCTGROUP BY更快,因为GROUP BY会多做一次分组和聚合计算;
  • 当需要 “分组 + 汇总” 时:只能用GROUP BYDISTINCT无法实现;
  • 特殊情况:如果表中存在大量重复记录,GROUP BYDISTINCT的效率差异可能很小(现代数据库会自动优化),但优先选择逻辑更简洁的语法。

三、常见误区(小白避坑)

  1. 误区 1:GROUP BY 可以替代 DISTINCT 做单纯去重错!虽然 GROUP BY 能间接得到唯一值,但会多做聚合计算,效率低且代码冗余,单纯去重就用 DISTINCT。

  2. 误区 2:SELECT 里可以写非分组、非聚合的字段错!比如 “按 user_id 分组,SELECT 里写 order_id”,会报错(因为一个小组有多个 order_id,数据库不知道返回哪一个)。

  3. 误区 3:HAVING 可以替代 WHERE错!HAVING 是 “分组后筛选”,只能用聚合函数;WHERE 是 “分组前筛选”,不能用聚合函数。比如 “筛选金额≥100 的订单再分组”,必须用 WHERE,不能用 HAVING。

  4. 误区 4:GROUP BY 对多个字段分组时,顺序无关错!分组顺序会影响中间过程(但最终结果的字段值顺序不影响),比如 “按日期 + 顾客” 分组和 “按顾客 + 日期” 分组,分组逻辑不同,但最终结果的汇总值一致。

四、总结

场景需求推荐语法核心逻辑
单纯去重(如不重复的顾客编号)SELECT DISTINCT 字段 FROM 表去重→返回唯一值
统计不重复值数量(如顾客总数)SELECT COUNT (DISTINCT 字段)去重→计数
按分组做汇总(如每个顾客的总消费)SELECT 分组字段,聚合函数 FROM 表 GROUP BY 分组字段分组→聚合计算
分组后筛选汇总结果(如总消费 > 100 的顾客)GROUP BY + HAVING 聚合条件分组→聚合→筛选汇总结果

记住:GROUP BY的核心是 “分组 + 汇总”,DISTINCT的核心是 “单纯去重”,不要用错场景。刚开始可以先记住 “需要统计、求和就用 GROUP BY,只需要去重就用 DISTINCT”,多练几次就能熟练区分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值