首页/数据/SQL 速查/占比与比率计算
聚合与窗口函数54 条

占比与比率计算

比率 = 部分 / 整体:用聚合相除并防止整数除法与除零;MySQL 与 PostgreSQL 的整数除法行为不同。

SQL 速查数据更新于 2026-10-13

占比与比率怎么算

比率等于部分除以整体,用聚合相除时有两个必须注意的点:整数除法会先截断,分母可能为 0。计算全局占比时常用 SUM(…) OVER () 取到总合计当作分母,省掉再写一条查询。

基本信息

基本形态部分除以整体,如 COUNT(*) / SUM(COUNT(*)) OVER ()
整数除法MySQL 的 / 返回小数;PostgreSQL 的整数相除先截断
防除零分母统一套 NULLIF(x, 0)
百分比乘 100.0 先把小数引入,避免先截断再放大
分组占比配合 SUM(…) OVER () 拿到所有分组的合计作为分母
精度控制外层用 ROUND 限定小数位

分组占比示例

分组占比示例
SELECT city,
       COUNT(*)                                          AS cnt,
       ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 2) AS pct
FROM users
GROUP BY city
ORDER BY cnt DESC;
-- SUM(COUNT(*)) OVER () 是所有城市的用户总数,作为分母
-- 各城市占比相加约等于 100,受舍入影响可能有 0.01 级偏差

PostgreSQL 与条件比率

PostgreSQL 与条件比率
-- PostgreSQL 里整数相除先截断,必须把小数提前引入
SELECT count(*) FILTER (WHERE status = 1) AS paid,     -- PG 支持 FILTER 条件聚合
       ROUND(100.0 * count(*) FILTER (WHERE status = 1)
             / NULLIF(count(*), 0), 2)        AS paid_pct
FROM orders;

要点与坑

要点说明后果
分母选择整体量,常用窗口合计分母选错会出现占比之和不为 100
整数除法PG 先截断,MySQL 返回小数比率整列变成 0
除零保护分母为 0 时报错或返回 NULL用 NULLIF 兜底
舍入各分组分别舍入相加可能与 100 有微小偏差
NULL 传播分子或分母为 NULL结果为 NULL,需要分类讨论

典型使用场景

  • 各渠道、各城市占比,用于大盘分析
  • 转化率:分子是转化量,分母是曝光或点击量
  • 同比环比:本期与上期相比的增长比例
  • 达成率:实际完成除以目标值
  • 缺陷率、故障率这类质量指标
  • 分桶占比:观察指标分布是否集中
  • 份额分析:某商品销量占该品类总量的比例,分母用窗口合计一次算出
占比之和不必严格等于 100:各分组独立舍入后,相加可能与 100 相差 0.01 到 0.1 个百分点,报表说明里最好注明“合计可能因舍入略有偏差”。
分子分母要同源:占比的两侧必须来自同一时间窗与同一过滤条件,否则会算出大于 100% 的值。改查询时两边一起改,别只改一半。
分母为 0 时两库行为不同:MySQL 返回 NULL 并产生告警,PostgreSQL 直接报 division by zero。跨库 SQL 一律用 NULLIF(分母, 0) 包住,避免库间差异引发线上故障。

易错点

  • 在 PostgreSQL 里直接整数相除:先截断再放大,比率整列都是 0,必须把小数提前引入
  • 分母写错:用分组自身的值当分母,算出的占比不成比例
  • 除零未保护:PG 直接报错中断查询,MySQL 返回 NULL 且带告警
  • 分组占比里漏掉 OVER ():变成每行除以自身,结果恒为 1

数据来源与参考

  • MySQL 8.0 Reference Manual · Aggregate Functions
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌