直接用 SUM() OVER(PARTITION BY) 算不出占比,因为其分母仅为分组总和,而占比需“当前行值 ÷ 对应分母”;分组内占比须用 sales / SUM(sales) OVER(PARTITION BY region),并转浮点防整除截断;全局占比则用 sales / SUM(sales) OVER();切忌误加 ORDER BY 导致分母变为累积和。

为什么直接用 SUM() OVER(PARTITION BY) 算不出占比?
因为 SUM() OVER(PARTITION BY ...) 只能算分组内总和,而占比需要「当前行值 ÷ 所有行总和」或「当前行值 ÷ 当前分组总和」——两者分母不同。很多人误以为加个 PARTITION BY 就能自动对应到全局分母,结果除出来全是 1 或报错。
怎么写才能得到正确的分组内占比?
分组内占比 = 当前行值 ÷ 该分组的总和,必须用两个窗口函数配合:一个算当前行值(通常就是原始字段),另一个用 SUM() OVER(PARTITION BY ...) 算分组和,再相除。注意强制转为 FLOAT 或 DECIMAL,否则整数除法会截断小数。
SELECT product, region, sales, sales * 1.0 / SUM(sales) OVER(PARTITION BY region) AS pct_in_region FROM sales_table;- 如果
sales是INT,不乘1.0或加::DECIMAL(5,4),SQL Server/PostgreSQL 会做整数除法,结果全为 0 或 1 - MySQL 8.0+ 同理,推荐显式写
sales / SUM(sales) OVER(PARTITION BY region) + 0.0避免隐式类型陷阱
想算占整个表的百分比,分母不能用 PARTITION BY
这时分母是全表总和,应该用空窗口定义:SUM(sales) OVER(),不是 PARTITION BY。混淆这两者是常见错误源头。
- 分组内占比:分母是
SUM(sales) OVER(PARTITION BY region) - 全局占比:分母是
SUM(sales) OVER()(括号里为空) - 别写成
SUM(sales) OVER(PARTITION BY region) / SUM(sales) OVER()来“手动归一化”——这算的是分组和占全局和的比例,不是单行占比
ORDER BY 在窗口里会影响结果吗?
在纯 SUM() OVER(PARTITION BY ...) 中加 ORDER BY 会变成累积和(running total),不再是分组总和,占比结果完全错误。除非你明确要计算“截止当前行的占比”,否则窗口定义中不要加 ORDER BY。
- 正确:
SUM(sales) OVER(PARTITION BY region) - 错误(无意中):
SUM(sales) OVER(PARTITION BY region ORDER BY date)→ 每行分母变小,占比虚高 - 如果真需要累积占比,得另起一列,并清楚命名如
cumulative_pct,避免误解
实际跑之前,先用 SELECT *, SUM(sales) OVER(PARTITION BY region) AS grp_sum 查看分母是否符合预期——这是最容易被跳过的验证步骤。

















