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 测试的置信区间,又必须用样本公式。选错一个函数,数字就偏了,而且很难从结果里一眼看出来。