别再算错了:SQL AVG() 函数的 NULL 陷阱详解(三个解法让你的数据分析不再出错)

前言

三位数据分析师走进会议室。他们被要求计算同一个数据库中的员工平均薪资。

分析师 A 报告:67,500 元

分析师 B 报告:54,000 元

分析师 C 报告:72,000 元

没有人打错字。没有查询报错。三个查询都成功执行了——而且从技术上讲,这三个答案都是「正确」的。

这是一个令人不安的真相:如果你在使用 SQL 的 AVG() 函数时,不了解它如何处理 NULL 值,你的数据分析很可能是错的。更糟的是,你永远不会收到错误消息告诉你这件事。

读完本文,你将学会:

  • ✅ 理解 AVG() 函数如何处理 NULL 值的底层逻辑

  • ✅ 识别哪些场景下 NULL 排除会导致错误的业务洞察

  • ✅ 掌握三种实用的 NULL 处理方法(COALESCE、WHERE、CASE)

  • ✅ 使用决策框架快速选择正确的平均值计算方式

  • ✅ 避免 90% 初学者都会犯的 AVG() 使用错误

博主提醒:这不是一个 SQL 语法错误,而是一个设计特性。但如果你不理解它,同样的数据可能会给你三个完全不同的平均值,而你永远不知道哪个才是你真正需要的。


一、问题复现:为什么三个人算出了三个不同的平均值?

1.1 真实场景还原

假设我们有一个员工表,包含 5 名员工的薪资信息:

CREATE TABLE employees (
    employee_id INT,
    name VARCHAR(100),
    salary DECIMAL(10,2)
);

INSERT INTO employees VALUES
(1, '张三', 70000),
(2, '李四', 65000),
(3, '王五', NULL),      -- 新入职员工,薪资尚未设定
(4, '赵六', NULL),      -- 合同工,无底薪
(5, '孙七', 75000);

现在,三位分析师分别执行了不同的查询:

分析师 A 的查询:

SELECT AVG(salary) AS avg_salary
FROM employees;

-- 结果:70,000
-- 计算方式:(70000 + 65000 + 75000) / 3 = 70,000

分析师 B 的查询:

SELECT AVG(COALESCE(salary, 0)) AS avg_salary
FROM employees;

-- 结果:42,000
-- 计算方式:(70000 + 65000 + 0 + 0 + 75000) / 5 = 42,000

分析师 C 的查询:

SELECT AVG(salary) AS avg_salary
FROM employees
WHERE salary IS NOT NULL;

-- 结果:70,000(与查询 A 相同,但意图更明确)

1.2 真相揭秘:AVG() 的隐藏行为

大多数初学者认为 AVG() 的工作方式是这样的:

  1. 取得列中的所有数字

  2. 加总起来

  3. 除以行数

  4. 返回平均值

但实际上,AVG() 的真实行为是:

步骤 初学者以为的 AVG() 实际的行为
1. 数据选择 取所有行的值 只取非 NULL 的值
2. 求和 加总所有值 只加总非 NULL 的值
3. 计数 除以总行数 除以非 NULL 值的数量
4. 返回 返回结果 返回结果(完全忽略 NULL)

💡 关键点AVG() 会自动排除 NULL 值,这不是 bug,而是 SQL 标准的设计特性。NULL 在 SQL 中代表「未知」或「不适用」,不等于零。


二、NULL 排除的设计原理:什么时候这是正确的?

2.1 为什么 SQL 要这样设计?

SQL 将 NULL 视为「未知」或「不适用」,而不是「零」。这是一个深思熟虑的设计决策。

2.2 三个合理的场景

场景 1:产品评分系统

-- 电商平台的产品评分表
-- 部分产品有评分,部分产品还未被评分
SELECT AVG(rating) AS avg_rating
FROM products;
解读方式 结果 是否合理
✅ 已被评分产品的平均分 4.5 星 合理:反映真实用户评价
❌ 将未评分当作 0 星 2.1 星 不合理:未评分 ≠ 差评

场景 2:问卷调查的满意度

-- 客户满意度调查(1-10 分)
-- 许多客户跳过了这个问题
SELECT AVG(satisfaction_score) AS avg_satisfaction
FROM surveys;

正确理解:回答问题的客户的平均满意度

错误理解:将未回答视为 0 分不满意

场景 3:员工绩效奖金

-- 大多数员工没有绩效奖金
SELECT AVG(bonus_amount) AS avg_bonus
FROM employees;

正确理解:获得奖金的员工的平均奖金额

错误理解:所有员工的平均奖金(应该包括零奖金员工)

🎯 设计原则:当 NULL 真正代表「不适用」或「未知」时,排除它们是正确的。问题在于,你的 NULL 到底代表什么?


三、危险场景:NULL 排除导致的分析错误

3.1 错误案例 1:销售团队业绩统计

业务背景

  • 销售团队按提成工作

  • 大部分销售每月都有业绩

  • 少数销售这个月业绩为零,在系统中记录为 NULL

-- ❌ 错误查询:只统计了有业绩的销售
SELECT AVG(commission) AS avg_commission
FROM sales_reps
WHERE month = '2025-10';

-- 结果:4,500 元
-- 问题:排除了无业绩的销售,夸大了平均业绩

向管理层报告:「本月平均提成 4,500 元」

实际情况:包含零业绩销售后,真实平均只有 3,200 元

-- ✅ 正确查询:将 NULL 视为零提成
SELECT AVG(COALESCE(commission, 0)) AS avg_commission
FROM sales_reps
WHERE month = '2025-10';

-- 结果:3,200 元
-- 说明:真实反映了团队整体表现

3.2 错误案例 2:网站用户行为分析

业务背景

  • 分析用户在网站停留时长

  • NULL 代表用户立即跳出(0 秒停留)

-- ❌ 错误查询:只统计了有互动的用户
SELECT AVG(session_duration_seconds) AS avg_duration
FROM user_sessions
WHERE DATE(session_start) = '2025-10-25';

-- 结果:180 秒(3 分钟)
-- 问题:数据看起来很好,但忽略了跳出用户

后果

  • 仪表板显示用户互动良好

  • 实际上 40% 的用户立即跳出

  • 产品经理做出了错误的优化决策

-- ✅ 正确查询:同时展示两个视角
SELECT 
    AVG(COALESCE(session_duration_seconds, 0)) AS avg_including_bounces,
    AVG(session_duration_seconds) AS avg_excluding_bounces,
    COUNT(*) AS total_sessions,
    COUNT(session_duration_seconds) AS engaged_sessions
FROM user_sessions
WHERE DATE(session_start) = '2025-10-25';

-- 结果展示:
-- avg_including_bounces: 108 秒(包含跳出)
-- avg_excluding_bounces: 180 秒(排除跳出)
-- total_sessions: 1,000
-- engaged_sessions: 600
-- 业务洞察:40% 跳出率需要优化落地页

3.3 错误案例 3:学生成绩统计

业务背景

  • 期末考试成绩统计

  • 部分学生缺考(记录为 NULL)

-- ❌ 错误查询:只统计了参加考试的学生
SELECT AVG(test_score) AS avg_score
FROM test_results
WHERE exam_id = 'FINAL_2025';

-- 结果:78 分
-- 问题:缺考学生应该计为 0 分,但被排除了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值