SQL无内置COEFFICIENT_OF_VARIATION函数,需用STDDEV_SAMP()/AVG()手动计算CV,注意过滤单行组、防除零(NULLIF)、限定均值为正,并警惕异常值及CV突变等业务信号。

SQL里没有直接的COEFFICIENT_OF_VARIATION函数
标准差除以平均值(即变异系数 CV)在统计学中常用于比较不同量纲或量级的分组波动程度,但主流 SQL 引擎(如 MySQL、PostgreSQL、SQL Server)均未内置 COEFFICIENT_OF_VARIATION 函数。你得手动组合 STDDEV() 和 AVG(),且必须注意分母为零、空值、样本/总体标准差差异等实际问题。
用STDDEV_SAMP和AVG配合计算分组CV
以 PostgreSQL 或 BigQuery 为例,STDDEV_SAMP() 是样本标准差(分母为 n−1),更常用;若需总体标准差,改用 STDDEV_POP()。关键点在于:每组必须至少有 2 行才可算样本标准差,否则 STDDEV_SAMP() 返回 NULL;而 AVG() 对单行也返回该值,此时直接相除会出错或失真。
- 先用
HAVING COUNT(*) > 1过滤掉单行组,避免无意义的 CV - 用
NULLIF(AVG(x), 0)防止除零错误——若某组平均值为 0,CV 无定义,应显式排除或标记 - CV 本身无单位,但对负均值组要谨慎:比如利润为负且波动大时,CV 符号可能误导,建议加条件限定
AVG(x) > 0
SELECT category, ROUND(STDDEV_SAMP(sales) / NULLIF(AVG(sales), 0), 3) AS cv FROM sales_table GROUP BY category HAVING COUNT(*) > 1 AND AVG(sales) > 0;
MySQL 8.0+ 需显式处理NULL和除零
MySQL 不支持 NULLIF 在聚合后直接用于除法右侧(早期版本甚至不支持窗口内嵌套聚合),且 STDDEV() 默认是 STDDEV_SAMP(),但行为在 5.7 和 8.0 间有细微差别。稳妥写法是用 CASE 显式拦截异常分支:
-
AVG(x) = 0→ 返回NULL或预设标记值(如-1) -
COUNT(*) = 1→STDDEV()结果不可靠,跳过或标为NULL - 结果建议用
ROUND(..., 4),CV 通常保留 3–4 位小数已足够判别波动强弱
SELECT
dept,
CASE
WHEN AVG(score) = 0 OR COUNT(*) = 1 THEN NULL
ELSE ROUND(STDDEV(score) / AVG(score), 4)
END AS cv
FROM exam_results
GROUP BY dept;
CV 大于 1 意味着什么?别只看数值
CV > 1 表示标准差超过均值,常见于低频高波动数据(如单日订单量、故障间隔时间)。但这不自动等于“异常”——如果业务本身具有长尾特性(如 SaaS 客户 ARPU),高 CV 反而是常态。真正要警惕的是:CV 在时间维度上突变(比如本周 CV 较上周翻倍),或同类型分组间 CV 差异过大(如华东 CV=0.3,华南 CV=1.8)。这些信号比绝对值更有分析价值。
另外,CV 对异常值敏感。一个极大值会让 STDDEV() 暴涨,CV 失真。必要时先用 PERCENTILE_CONT(0.5) 看中位数,或加 WHERE x BETWEEN ... 做简单截断。

















