必须用 count() over(partition by dept) 计算每组行数并广播到各行,而非count()或sum(1);分母用count(*) over()获过滤后总行数;乘1.0防整除截断;勿冗余写rows between子句;null在partition by中被归为一组,需用coalesce处理以对齐group by语义。

用 SUM() OVER(PARTITION BY ...) 先算分组总数
直接在 SELECT 里写 COUNT(*) 或 SUM(1) 是错的——它不会按组聚合,而是返回当前行的值(通常是 1)。必须用窗口函数把每组的总行数“广播”到每一行。比如想算每个部门员工数占全表比例,得先拿到每个部门的员工数:
SELECT dept, name,
COUNT(*) OVER (PARTITION BY dept) AS dept_count
FROM employees;注意这里不能用 COUNT(dept),因为 COUNT() 窗口版对 NULL 不敏感,但语义上我们就是要统计该组所有行(含可能的 NULL 字段),所以 COUNT(*) 最稳妥。用 COUNT(*) OVER() 拿全表总行数
分母要是整个结果集的总行数,不是表原始行数(因为可能有 WHERE 过滤)。窗口函数 COUNT(*) OVER() 不带 PARTITION BY 就表示“全局帧”,会把过滤后的总行数填到每一行:
一款AI工具,主要用于在主代理响应前,并行运行Kimi K2.5和GPT 5.3 Codex,注入双方观点以增强认知多样性,适合需要提升相关任务效率的用户。
SELECT dept, name,
COUNT(*) OVER (PARTITION BY dept) * 1.0 / COUNT(*) OVER() AS dept_ratio
FROM employees
WHERE status = 'active';乘以 1.0 是防止整数除法截断(尤其在 PostgreSQL 和 SQL Server 中常见);MySQL 8.0+ 默认保留小数,但显式转浮点更可靠。避免 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 的冗余写法
有人习惯给 OVER() 显式加帧定义,比如 COUNT(*) OVER(ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)。这在逻辑上等价于 COUNT(*) OVER(),但多写十几个字符,还容易拼错。更关键的是:如果后续加了 ORDER BY 到窗口定义里,帧默认会变成 RANGE 模式,导致重复值被合并计数——而占比计算绝不该受排序影响。所以只要不需要逐行累积,就别碰 ROWS 或 RANGE 子句。
NULL 值会让 GROUP BY 和窗口函数行为不一致
如果分组字段(如 dept)有 NULL,PARTITION BY dept 会把所有 NULL 归为同一组,但传统 GROUP BY dept 在多数数据库里把 NULL 视作独立分组(标准行为)。这意味着:用窗口函数算出的 “NULL 部门占比” 可能和你用 GROUP BY + SUM 手动验证的结果不一致。遇到这种情况,要么提前用 COALESCE(dept, 'UNKNOWN') 处理 NULL,要么确认业务是否真把 NULL 当作一个有效分组——这点常被忽略,直到报表数字对不上才回头查。










