📊 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,否则语义错误
相关推荐
哈__1 小时前
MCP 协议落地实践:国产化数据库 AI 一站式 SQL 诊断调优方案
数据库·人工智能·sql
用户298698530141 小时前
Java 创建 CSV 文件的三种实用方法:从零构建、数组写入与 Excel 转换
java·后端·excel
玉宇夕落2 小时前
Cheerio虚拟DOM原理
后端
geovindu2 小时前
go: Recursion Algorithm
开发语言·后端·算法·golang·递归算法
用户2930750976692 小时前
深入理解 RAG 文档切割:从知识库到向量数据库的关键一步
后端
geovindu2 小时前
CSharp: Composite Pattern
开发语言·后端·c#·组合模式·结构型模式
宇图SHARE2 小时前
别再用 Python 写 Agent 前端了!Vue3 + NestJS + TypeScript 全栈方案,开发效率翻倍
前端·后端
吃饱了得干活2 小时前
Spring Cloud Gateway限流:从Redis到Sentinel的三种方案
后端·spring cloud
IT_陈寒2 小时前
Python的GIL让我以为CPU跑满了,结果...
前端·人工智能·后端