MySQL用VARIANCE()或VAR_POP()、STDDEV()或STDDEV_POP()直接计算总体方差和标准差;PostgreSQL必须显式写VAR_POP()/STDDEV_POP();SQL Server需用VAR()((COUNT()-1.0)/COUNT(*))校正;跨库需警惕STDDEV语义差异。

MySQL里直接用VARIANCE()和STDDEV_POP()就行,别手写平方和公式
MySQL 5.7+ 原生支持聚合函数计算总体方差和标准差,VARIANCE()等价于VAR_POP(),STDDEV()默认也是STDDEV_POP()(不是样本版)。手算容易漏除以N还是N-1,直接调用更稳。
-
VAR_POP(col)= 总体方差 =SUM((col - AVG(col))²) / COUNT(*) -
STDDEV_POP(col)= 总体标准差 =SQRT(VAR_POP(col)) - 如果表为空,两个函数都返回
NULL,不是0 —— 注意空值判断逻辑 - 数值列含
NULL时,这些函数自动跳过NULL行,不参与计算也不报错
PostgreSQL必须写VAR_POP()和STDDEV_POP(),VAR_SAMP()是默认但不是你要的
PostgreSQL里VAR_SAMP()和STDDEV_SAMP()才是默认函数(分母为N-1),对应“样本”统计。如果你要的是“总体”方差/标准差(比如全量用户、全年数据、无抽样场景),必须显式写VAR_POP(),否则结果偏大。
- 常见错误:
SELECT STDDEV(salary) FROM emp;→ 实际算的是样本标准差,不是你Excel里用=STDEVP()的结果 - 正确写法:
SELECT VAR_POP(salary), STDDEV_POP(salary) FROM emp; - PostgreSQL不支持
VARIANCE()这种别名,只认VAR_POP/VAR_SAMP - 浮点精度没问题,但整数列传入后结果仍是
double precision,别用INT类型变量接结果
SQL Server没有VAR_POP,得用VAR()和STDEV()再手动转成总体版
SQL Server的VAR()和STDEV()固定按样本公式算(分母N-1),没有内置总体版本。要得到总体方差,得用VAR() * (COUNT(*) - 1) / COUNT(*)校正;标准差同理开方前先校正方差。
- 示例:总体标准差 =
SQRT(VAR(x) * (COUNT(*) - 1.0) / COUNT(*)) - 注意
- 1.0而不是- 1,避免整数除法截断(尤其COUNT(*)小的时候) - 单行数据时
VAR()返回NULL(因为分母为0),校正式也会崩,得加CASE WHEN COUNT(*) = 1 THEN 0 ELSE ... END - 窗口函数下也能用,但
VAR() OVER(...)仍是样本版,同样要校正
跨数据库移植时,STDDEV含义不统一,必须查文档再写
同一个函数名在不同库语义可能相反:MySQL和Oracle的STDDEV()默认是总体版,PostgreSQL和SQL Server却是样本版。别凭经验写,尤其当SQL要跑在多个环境时。
- Oracle 12c+:
STDDEV()= 样本标准差,STDDEV_POP()= 总体版 —— 和PG一致,和MySQL相反 - SQLite:只有
stddev()扩展函数(需加载),且行为依赖编译选项,生产环境慎用 - 迁移脚本里如果看到
STDDEV(col),第一反应不是“能跑”,而是“它在这库到底算谁?” - 最保险的做法:统一用
STDDEV_POP()+ 显式检查目标库是否支持;不支持就走校正公式
事情说清了就结束。方差和标准差的“总体/样本”之分,不是数学洁癖,是业务口径——比如算全公司薪资离散度,用样本公式会高估波动;而做A/B测试的置信区间,又必须用样本公式。选错一个函数,数字就偏了,而且很难从结果里一眼看出来。










