You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL中CASE表达式带与不带ELSE子句的查询差异问题

PostgreSQL 两段薪资查询差异解答
-- 查询1:带ELSE 0分支
SELECT
       AVG(
            CASE
                  WHEN emp_no = 90689 THEN salary
                  ELSE 0
             END
       ) AS emp_90689_salary
FROM salaries;

-- 查询2:省略ELSE分支
SELECT
       AVG(
            CASE
                  WHEN emp_no = 90689 THEN salary
             END
       ) AS emp_90689_salary
FROM salaries;

问题1:两段查询的核心差异

两段语句的唯一核心区别是CASE表达式对不满足emp_no = 90689条件的行的返回值规则不同:

  • 查询1显式声明ELSE 0:所有非目标员工的行,CASE表达式返回数值0
  • 查询2省略ELSE子句:所有非目标员工的行,CASE表达式返回NULL

问题2:返回不同结果的底层原因

结果差异来自两个SQL标准层面的固定规则,所有支持标准SQL的数据库均遵循该逻辑,并非PostgreSQL独有特性:

  • CASE表达式的默认返回规则:如果未编写ELSE子句,所有不匹配WHEN条件的行,默认返回值为NULL,不存在“隐式过滤掉非目标行”的逻辑,表中每一行都会进入CASE表达式做计算。
  • AVG聚合函数的统计规则:AVG计算平均值时,会直接忽略所有值为NULL的记录,仅对非NULL的数值做求和、计数统计;但0是合法的数值类型值,会被正常计入统计的总计数(即平均值计算的分母)。

举个直观的计算示例:假设salaries表总共有100万条薪资记录,其中工号90689的员工共有3条调薪记录,薪资分别为60000、70000、80000:

  • 查询1的计算过程:总求和值为60000+70000+80000 + 0*999997 = 210000,总计数为全表100万行,最终平均值为0.21,该结果无实际业务参考意义,相当于把其他所有员工的薪资按0计算,大幅拉低了均值。
  • 查询2的计算过程:AVG直接忽略999997个NULL值,仅统计3条非NULL的目标员工记录,总求和值为210000,总计数为3,最终平均值为70000,和该员工实际平均薪资一致。

认知补充

你之前认为“省略ELSE子句时仅会针对工号90689的员工计算薪资平均值”,这个结论在最终输出数值上是符合预期的,但底层逻辑并非查询提前过滤了非目标员工的行:这种写法是全表逐行计算CASE返回值,再由AVG跳过NULL值得到结果;和添加WHERE emp_no = 90689先过滤行再计算AVG的写法相比,最终数值一致,但执行路径存在差异,数据量较大时WHERE过滤的写法性能会明显更优。


内容的提问来源于stack exchange,提问作者Amir Monir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:45:44