📊 SQL 入门 Day 4:聚合函数 — COUNT / SUM / AVG / MIN / MAX

📌 一句话总结

聚合函数对一组行进行计算并返回一个汇总值 ,是 SQL 做统计分析的基石。常与 GROUP BY 配对使用(今天的铺垫)。


1. 五大聚合函数一览

函数 作用 适用类型 NULL 处理
COUNT(*) 统计行数 任何 所有行都算
COUNT(column) 统计非 NULL 值个数 任何 剔除 NULL
SUM(column) 求和 数值 忽略 NULL
AVG(column) 求平均值 数值 忽略 NULL
MIN(column) 求最小值 数值/字符串/日期 忽略 NULL
MAX(column) 求最大值 数值/字符串/日期 忽略 NULL
sql 复制代码
-- 基础示例
SELECT
    COUNT(*) AS total_employees,
    COUNT(department_id) AS has_dept,        -- 比 COUNT(*) 少(有空部门)
    COUNT(DISTINCT department_id) AS unique_depts,  -- 去重统计
    AVG(salary) AS avg_salary,
    SUM(salary) AS total_salary,
    MIN(salary) AS min_salary,
    MAX(salary) AS max_salary
FROM employees;

2. NULL 的处理陷阱

sql 复制代码
-- 建测试表
CREATE TABLE scores (name TEXT, score INT);
INSERT INTO scores VALUES ('张三', 85), ('李四', NULL), ('王五', 92), ('赵六', NULL);

-- 不同 COUNT 的区别
SELECT
    COUNT(*)        AS total_rows,    -- 4(所有行)
    COUNT(score)    AS has_score,     -- 2(忽略 NULL)
    AVG(score)      AS avg_score,     -- 88.5((85+92)/2,不是 /4)
    SUM(score)/4    AS wrong_avg,     -- 44.25(千万别这么写)
    SUM(score)/COUNT(score) AS correct_avg  -- 88.5
FROM scores;

⚠️ AVG + NULL 的坑

AVG 内部是 SUM / COUNT(column)不是 SUM / COUNT(*)。如果行的 NULL 太多,算出来的平均值可能比预期高(因为分母变小了)。

sql 复制代码
-- 处理方式 1:把 NULL 视为 0
SELECT AVG(COALESCE(score, 0)) AS avg_including_zero FROM scores;
-- (85+0+92+0)/4 = 44.25

-- 处理方式 2:明确业务语义
-- "缺考"和"考了0分"是两回事,业务上通常是 方式1=实际平均 方式2=含缺考

3. DISTINCT 聚合

sql 复制代码
-- 去重统计
SELECT
    COUNT(DISTINCT city) AS unique_cities,
    SUM(DISTINCT salary) AS sum_unique_salaries  -- 不重复薪资之和(用得少)
FROM employees;

COUNT(DISTINCT col) 非常常用,「有多少种不同的值」。 SUM(DISTINCT col) 很罕见,只有在「每种值只算一次」的特殊业务才有用。


4. 聚合 + 条件过滤

三步走:WHERE 先过滤 → 再聚合。

sql 复制代码
-- 查询技术部的薪资统计
SELECT
    COUNT(*) AS tech_count,
    AVG(salary) AS tech_avg_salary
FROM employees
WHERE department = '技术部';

-- 多条件组合
SELECT
    COUNT(*) AS count_high_salary,
    AVG(salary) AS avg_high_salary
FROM employees
WHERE salary > 15000
  AND hire_date >= '2023-01-01';

WHERE vs HAVING(预告)

  • WHERE:在聚合前过滤行
  • HAVING:在聚合后过滤组
sql 复制代码
-- WHERE 过滤掉薪资为 NULL 的行再聚合
SELECT AVG(salary) FROM employees WHERE salary IS NOT NULL;
-- 上面等价于 SELECT AVG(salary) FROM employees;(AVG 本身就忽略 NULL)

5. 实战案例

案例 1:报表统计

sql 复制代码
-- 公司整体报表
SELECT
    COUNT(*) AS 员工总数,
    COUNT(CASE WHEN gender = '女' THEN 1 END) AS 女性人数,
    ROUND(AVG(salary), 0) AS 平均薪资,
    MAX(salary) AS 最高薪资,
    MIN(salary) AS 最低薪资,
    MAX(salary) - MIN(salary) AS 薪资差距
FROM employees;

案例 2:日期聚合

sql 复制代码
-- 最早和最晚入职日期
SELECT
    MIN(hire_date) AS 最早入职,
    MAX(hire_date) AS 最晚入职,
    DATEDIFF(MAX(hire_date), MIN(hire_date)) AS 公司历史天数  -- MySQL
FROM employees;

案例 3:数据质量检测

sql 复制代码
-- 检查各字段的完整性
SELECT
    COUNT(*) AS total,
    COUNT(email)     AS has_email,
    COUNT(phone)     AS has_phone,
    COUNT(department_id) AS has_dept,
    COUNT(salary)    AS has_salary
FROM employees;
-- has_email < total 说明有人没填邮箱

6. 聚合函数与非聚合列

sql 复制代码
-- ❌ 错误写法
SELECT name, AVG(salary) FROM employees;
-- name 是非聚合列,但有 100 行,AVG(salary) 只有 1 个值
-- 数据库不知道要显示哪个 name
-- MySQL 默认会取第一个 name(不报错但语义错误!)
-- PostgreSQL / SQLite 直接报错

-- ✅ 正确做法
SELECT AVG(salary) FROM employees;           -- 只查聚合
SELECT department_id, AVG(salary)            -- 加 GROUP BY
FROM employees
GROUP BY department_id;

⚠️ 规则: SELECT 中出现非聚合列,必须出现在 GROUP BY 中(MySQL 宽松模式除外,但不要依赖)。


📝 要点总结

函数 关键点
COUNT(*) 统计行数,含 NULL
COUNT(col) 统计非 NULL 行数
AVG(col) 忽略 NULL 后计算,分母不含 NULL
MIN/MAX 字符串按字典序,日期按时间序
NULL 所有聚合函数(除 COUNT(*))都忽略 NULL
DISTINCT COUNT(DISTINCT col) 去重计数
与非聚合列混用 必须配合 GROUP BY,否则语义错误
相关推荐
考虑考虑4 小时前
docker compose V2版本新属性
运维·后端·自动化运维
GreenTea7 小时前
7000 万 QPS、500 PB:OpenAI 如何用一个 Python 存储平台撑住 10 亿用户
后端·架构
Flynt7 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
Bs_MoneyMagnet7 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
GreenTea7 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
Bs_MoneyMagnet10 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计
IT_陈寒10 小时前
Vue的响应式更新把我坑惨了,原来问题出在这
前端·人工智能·后端
陌シ未央ゞ11 小时前
基于BM25算法和RRF实现的混合索引(java版)
人工智能·spring boot·后端·算法
第五页的你11 小时前
SpringBoot基础设施配置(Redis序列化,JJWT新版)
后端
吃饱了得干活11 小时前
RabbitMQ 原理解析(下):存储、集群与可靠投递
后端·rabbitmq