sql分组占比计算必须用sum() over(partition by department),不能用group by(会压缩行数);漏写partition by得全表和,误加order by变累计和;需转浮点防整除截断,并用nullif避免除零。

用 SUM() OVER(PARTITION BY ...) 先算出部门总薪资
窗口函数的关键在于“分组内聚合但不折叠行”,所以不能用 GROUP BY,而要用 OVER(PARTITION BY department)。直接对薪资求和时,必须确保是同一部门所有员工的 salary 相加,否则比例会错。
常见错误是漏写 PARTITION BY,导致算出的是全表总和;或者误写成 ORDER BY 导致累积和(SUM() OVER(ORDER BY ...)),结果完全不对。
-
SUM(salary) OVER(PARTITION BY department)是部门总薪资,每行都重复这个值 - 如果表里有空值(
NULL)的salary,SUM会自动跳过,不影响分母计算 - 部门名字段名假设为
department,实际请替换成你表中的真实列名(比如dept_name或org_id)
用当前行薪资除以部门总和得到占比
比例本质就是单行值除以同窗口的聚合结果,注意类型转换:多数数据库(如 PostgreSQL、SQL Server)中整数除整数会截断小数,MySQL 8.0+ 默认也如此。必须至少一侧转为浮点,否则 5000 / 25000 得到 0 而不是 0.2。
- 推荐写法:
salary * 1.0 / SUM(salary) OVER(PARTITION BY department) - 更明确的写法:
CAST(salary AS DECIMAL(10,4)) / SUM(salary) OVER(PARTITION BY department) - 别用
ROUND(..., 2)过早四舍五入,会放大误差;建议最后一步再格式化显示
处理零值或空部门的边界情况
如果某部门所有员工的 salary 都是 NULL,或部门字段本身为空(department IS NULL),SUM(...) OVER(...) 返回 NULL,此时除法结果也是 NULL —— 这通常是合理行为,但有些业务要求显示 0 或跳过。
- 避免除零错误:虽然
SUM不会返回0(空组返回NULL),但如果手动补了默认值(比如用COALESCE(SUM(...), 0)),就可能触发除零,需加NULLIF - 安全写法:
salary / NULLIF(SUM(salary) OVER(PARTITION BY department), 0) - 若想把
NULL部门单独归为一类,可写PARTITION BY COALESCE(department, 'UNKNOWN')
PostgreSQL / MySQL 8.0+ / SQL Server 的兼容性提醒
语法基本一致,但细节差异会影响结果精度和空值处理:
- PostgreSQL 对
NULL最严格,SUM遇全NULL返回NULL,除法也返回NULL - MySQL 8.0+ 默认开启
sql_mode=STRICT_TRANS_TABLES,但除零不会报错,只返回NULL - SQL Server 中
DECIMAL除法会保留精度,但要注意定义的位数,DECIMAL(5,2) / DECIMAL(5,2)可能溢出 - SQLite 不支持窗口函数(截至 3.45 版本),别在 SQLite 上试
实际跑的时候,最常被忽略的是隐式整数除法和 NULL 部门的分区逻辑——这两处一错,整列比例就全偏了。










