SQL入门:聚合函数—从入门到精通

一、什么是聚合函数?​

假设你是一家小商店的老板,每天会记录 “每笔订单的金额、购买的商品、下单时间”(这些记录存在数据库的 “订单表” 里)。​

如果想知道 “这个月一共卖了多少笔订单”“平均每笔订单花了多少钱”,总不能手动数、手动算吧?​

这时候就需要聚合函数:把表中的 “一堆数据”(多条订单记录)聚合成 “一个结果”(比如总订单数、平均金额),核心是 “从多到一” 的计算。​

二、5 个必学聚合函数:用法 + 例子 + 注意事项​

下面用 “订单表(orders)” 为例,表中有 3 个字段:order_id(订单编号)、user_id(顾客编号)、amount(订单金额,单位:元)、create_time(下单时间),先看表中数据(方便理解例子):

order_iduser_idamountcreate_time
1101502025-05-01
21021502025-05-01
3101802025-05-02
4103NULL2025-05-02
51021202025-05-03

1. COUNT ():统计 “有多少条记录”(最常用,含 COUNT (1))​

作用:数表中 “符合条件的记录数量”,比如 “有多少笔订单”“有多少个顾客下过单”。​

它有 4 种常用写法(新增COUNT(1)),区别要分清!​

(1)COUNT (*):统计 “所有记录”(包括空值)​

  • 不管字段里有没有空值(比如上面订单 4 的amount是 NULL),只要是一条完整的记录,就会被算进去。​
  • 例子:统计订单表一共有多少笔订单(包括金额为空的订单 4)
SELECT COUNT(*) AS 总订单数 FROM orders;
  • 结果:总订单数 = 5(因为表中一共 5 条订单记录,哪怕订单 4 金额是空的,也算一笔订单)。​

(2)COUNT (1):统计 “所有记录”(和 COUNT (*) 功能几乎一样)​

  • 原理:1是一个 “常量”,SQL 会给每一条记录 “临时加一个值为 1 的虚拟字段”,然后统计这个虚拟字段的数量 —— 只要是一条记录,就会有一个 “1”,所以最终结果和COUNT(*)相同,也包括空值记录。​
  • 例子:同样统计订单表总订单数(结果和COUNT(*)一致)
SELECT COUNT(1) AS 总订单数 FROM orders;
  • 结果:总订单数 = 5(和COUNT(*)一样,包含订单 4)。​
  • COUNT (1) 和 COUNT (*) 的区别与联系:​
  • 联系:99% 的场景下结果完全相同,都统计所有记录(包括空值),执行效率也几乎没有差异(现代数据库会自动优化,比如 MySQL、PostgreSQL 对两者的优化逻辑一致)。​
  • 区别:原理不同 ——COUNT(*)是直接统计记录行数,COUNT(1)是统计 “虚拟常量字段” 的数量;极端场景(比如表没有任何字段,仅用于存空记录)下COUNT(*)可用,COUNT(1)也可用,但实际业务中几乎遇不到。​
  • 小白建议:不用纠结,两者随便用,想简单记就记COUNT(*),如果看到别人写COUNT(1),知道它和COUNT(*)功能一样就行。​

(3)COUNT (字段名):统计 “该字段不为空的记录”​

  • 只数 “某个字段有值的记录”,如果字段是 NULL(空),就不算。​
  • 例子:统计 “金额有填写的订单” 有多少笔(排除订单 4)
SELECT COUNT(amount) AS 有金额的订单数 FROM orders;
  • 结果:有金额的订单数 = 4(订单 4 的amount是 NULL,被排除了)。​

(4)COUNT (DISTINCT 字段名):统计 “该字段不重复且不为空的记录”​

  • 先去重(比如同一个顾客下了多笔订单,只算一次),再统计数量,同时排除 NULL。​
  • 例子:统计 “有多少个不同的顾客下过单”(顾客 101 下了 2 笔,只算 1 次)
SELECT COUNT(DISTINCT user_id) AS 不同顾客数 FROM orders;
  • 结果:不同顾客数 = 3(顾客 101、102、103,共 3 人,订单 4 的user_id是 103,不为空,会被算进去)。​

COUNT () 系列注意事项:​

  • “空值(NULL)” 不是 “0” 或 “空字符串”:比如订单 4 的amount是 “没填”,不是 “0 元”,所以COUNT(amount)会排除它,但COUNT(*)和COUNT(1)会包含它。​
  • 不要用COUNT(字段名)统计总记录数:比如想算总订单数,用COUNT(*)或COUNT(1),别用COUNT(amount),因为会漏掉字段为空的记录。​

2. SUM ():计算 “数值的总和”(只对数字有效)​

作用:把 “数值型字段” 的所有值加起来,比如 “所有订单的总金额”“某个顾客的总消费”。​

  • 注意:只能算数字(比如amount是金额,是数字),不能算文字(比如user_id是顾客编号,虽然是数字,但本质是标识,一般不用 SUM 加)。​
  • 自动忽略 NULL:如果字段是 NULL(比如订单 4 的amount),计算时会跳过,不会把 NULL 当 0 算。​

例子 1:计算所有订单的 “总金额”(排除订单 4 的 NULL)

SELECT SUM(amount) AS 订单总金额 FROM orders;
  • 计算过程:50 + 150 + 80 + 120 = 400(订单 4 的 NULL 被跳过)​
  • 结果:订单总金额 = 400。​

例子 2:计算 “顾客 102” 的总消费(他下了订单 2 和 5)

SELECT SUM(amount) AS 顾客102总消费 
FROM orders 
WHERE user_id = 102; -- 只看顾客102的订单
  • 计算过程:150 + 120 = 270​
  • 结果:顾客102总消费 = 270。​

SUM () 注意事项:​

  • 只能用于 “数值字段”:如果对user_id用 SUM(比如SUM(user_id)),虽然语法不报错,但结果没意义(101+102+101+103+102=509,这个数字没有业务价值)。​

3. AVG ():计算 “数值的平均值”(只对数字有效)​

作用:求 “数值型字段” 的平均值,公式是 “总和 ÷ 不为空的记录数”(不是总记录数)。​

  • 自动忽略 NULL:和 SUM 一样,NULL 会被跳过,不参与计算。​

例子:计算所有订单的 “平均金额”(排除订单 4 的 NULL)

SELECT AVG(amount) AS 平均订单金额 FROM orders;
  • 计算过程:总和(400) ÷ 有金额的订单数(4) = 100​
  • 结果:平均订单金额 = 100。​

易错点提醒:​

  • 不是 “总和 ÷ 总记录数”:如果按总记录数 5 算,400÷5=80,这是错的!因为 AVG 会自动排除 NULL,只除以 “有值的记录数”。​

4. MAX ():找 “最大值”(支持数字、日期、文字)​

作用:从 “字段” 中找最大的值,比如 “最大的订单金额”“最新的下单时间”。​

  • 支持多种类型:​
  • 数字:找最大的数(比如金额最大);​
  • 日期:找最新的时间(比如最近的下单时间);​
  • 文字:按字典顺序找最后一个(比如用户名最大,用得少)。​

例子 1:找 “最大的订单金额”

SELECT MAX(amount) AS 最大订单金额 FROM orders;
  • 结果:最大订单金额 = 150(订单 2 的金额 150 是最大的)。​

例子 2:找 “最新的下单时间”

SELECT MAX(create_time) AS 最新下单时间 FROM orders;
  • 结果:最新下单时间 = 2025-05-03(订单 5 的时间是最晚的)。​

5. MIN ():找 “最小值”(和 MAX 相反)​

作用:从 “字段” 中找最小的值,用法和 MAX 完全相反,支持数字、日期、文字。​

例子 1:找 “最小的订单金额”(排除 NULL)

SELECT MIN(amount) AS 最小订单金额 FROM orders;
  • 结果:最小订单金额 = 50(订单 1 的金额 50 是最小的)。​

例子 2:找 “最早的下单时间”

SELECT MIN(create_time) AS 最早下单时间 FROM orders;
  • 结果:最早下单时间 = 2025-05-01(订单 1 和 2 的时间是最早的)。​

三、进阶:聚合函数 + GROUP BY(分组汇总)​

前面的例子都是 “对整个表做汇总”(比如所有订单的总金额),但实际中经常需要 “按类别汇总”—— 比如 “按日期分组,统计每天的订单金额”“按顾客分组,统计每个顾客的总消费”。​

这时候就要用GROUP BY 分组字段,意思是 “把表按某个字段分成几组,每组分别用聚合函数计算”。​

例子 1:按 “下单日期” 分组,统计每天的订单数(用 COUNT (1))和总金额​

需求:想知道 5 月 1 日、2 日、3 日每天各有多少笔订单,总金额是多少(这里用COUNT(1)统计订单数)。

SELECT 
  create_time AS 下单日期,  -- 按“下单日期”分组
  COUNT(1) AS 当日订单数,    -- 每组(每天)的订单数,用COUNT(1)
  SUM(amount) AS 当日总金额  -- 每组(每天)的总金额
FROM orders
GROUP BY create_time; -- 关键:按日期分组
  • 结果:​

| 下单日期 | 当日订单数 | 当日总金额 |​

|------------|------------|------------|​

| 2025-05-01 | 2 | 200(50+150) |​

| 2025-05-02 | 2 | 80(只有订单 3 的 80,订单 4 是 NULL) |​

| 2025-05-03 | 1 | 120 |​

  • 说明:这里用COUNT(1)和用COUNT(*)的结果完全一样,都是统计每天的总订单数。​

例子 2:按 “顾客” 分组,统计每个顾客的订单数(用 COUNT (*))和总消费

SELECT 
  user_id AS 顾客编号,
  COUNT(*) AS 顾客订单数,    -- 每个顾客的总订单数(包括金额NULL的)
  SUM(amount) AS 顾客总消费 -- 每个顾客的总金额(排除NULL)
FROM orders
GROUP BY user_id; -- 按顾客编号分组
  • 结果:​

| 顾客编号 | 顾客订单数 | 顾客总消费 |​

|----------|------------|------------|​

| 101 | 2 | 130(50+80) |​

| 102 | 2 | 270(150+120) |​

| 103 | 1 | NULL(订单 4 金额是 NULL,SUM 忽略后为 NULL) |​

四、再进阶:HAVING(筛选分组后的结果)​

用GROUP BY分组后,想筛选 “符合条件的组”,比如 “找出总消费超过 100 元的顾客”,这时候不能用WHERE(WHERE是筛选分组前的原始数据),必须用HAVING(专门筛选分组后的结果)。​

例子:找出 “总消费超过 100 元” 的顾客,同时统计他们的订单数(用 COUNT (1))

SELECT 
  user_id AS 顾客编号,
  COUNT(1) AS 顾客订单数,    -- 用COUNT(1)统计订单数
  SUM(amount) AS 顾客总消费
FROM orders
GROUP BY user_id
HAVING SUM(amount) > 100; -- 筛选总消费>100的组(顾客)
  • 结果:​

| 顾客编号 | 顾客订单数 | 顾客总消费 |​

|----------|------------|------------|​

| 101 | 2 | 130 |​

| 102 | 2 | 270 |​

  • 解释:顾客 103 的总消费是 NULL,不满足 “>100”,所以被排除;这里COUNT(1)统计的订单数和COUNT(*)一致。​

五、小白必记的 4 个核心原则​

  1. COUNT (*) 和 COUNT (1) 几乎无差别:都统计所有记录(包括空值),结果和效率差不多,不用纠结,随便用。​
  2. 聚合函数只能用于 “汇总”:不能单独用在WHERE里(比如WHERE SUM(amount) > 100是错的,必须用HAVING)。​
  3. 自动忽略 NULL:除了COUNT(*)和COUNT(1),其他聚合函数(SUM、AVG、MAX、MIN、COUNT (字段))都会跳过 NULL 值,不参与计算。​
  4. GROUP BY 和 SELECT 要对应:用GROUP BY 字段A时,SELECT里只能有 “分组字段 A” 和 “聚合函数”(比如SELECT user_id, SUM(amount)是对的,SELECT user_id, order_id是错的,因为order_id不是分组字段,也不是聚合函数)。​

六、总结:什么时候用哪个函数?

需求场景用哪个函数?需求场景用哪个函数?
统计所有记录数(最常用)COUNT (*) 或 COUNT (1)找最大的值(最大金额、最新时间)MAX (字段)​
统计有多少个不同的数值COUNT (DISTINCT 字段)找最小的值(最小金额、最早时间)MAX (字段)
统计某个字段有值的记录数COUNT (字段名)找最小的值(最小金额、最早时间)MIN (字段)
计算总和(金额、数量等)SUM (字段)按类别汇总(每天、每个顾客)GROUP BY + 聚合函数
计算平均值(平均金额等)AVG (字段)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值