首页/数据/SQL 速查/组内计数广播 COUNT(*) OVER
聚合与窗口函数54 条

组内计数广播 COUNT(*) OVER

不改行数地给每行附上组内统计(组大小、组内极值),常用于占比、排名并列判断与数据探查。

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

组内计数广播是什么

COUNT(*) OVER (PARTITION BY 维度) 把分组计数写到该分区的每一行上,不折叠行。它最常见的用法是「明细加组总数」一起展示,或者用外层条件筛掉不满足数量的分组(例如找出订单数超过 10 的用户并保留其明细)。语义上等价于 GROUP BY 之后再把统计结果连接回明细表,但一条语句就写完,优化器通常只扫一遍数据。MySQL 8 与 PostgreSQL 都支持。

基本信息

适用平台MySQL 8.0+ / PostgreSQL 11+
语义分区内计数并广播到该分区每一行,结果行数不变
与 GROUP BY 区别窗口函数不折叠行,聚合函数折叠行
等价改写LEFT JOIN 子查询 GROUP BY 的结果,再取计数列
过滤限制窗口函数不能写在 WHERE / HAVING,需包一层派生表或 CTE

典型使用场景

  • 明细列表里带上所属分组的总数,省掉一次额外查询
  • 筛选分组总量:订单数超过阈值的用户、消费额达标的客户
  • 算明细占组内比例的前置步骤(分母就来自这个广播值)
  • 找重复数据:按业务键分区,计数大于 1 的行即为重复
  • 数据质量校验:核对每组的明细行数与预期是否一致

基础用法与过滤

基础用法与过滤
-- 明细行 + 所属用户的订单总数
SELECT id, user_id, amount,
       COUNT(*) OVER (PARTITION BY user_id) AS user_order_cnt
FROM orders
WHERE created_at >= '2026-09-01';

-- 过滤「组内数量」必须包一层:窗口函数不能直接写在 WHERE
SELECT * FROM (
  SELECT id, user_id, amount,
         COUNT(*) OVER (PARTITION BY user_id) AS cnt
  FROM orders
) t
WHERE t.cnt > 10;

找重复与占比

找重复与占比
# 同一个手机号出现多次的行:cnt 大于 1 即重复
SELECT * FROM (
  SELECT id, phone,
         COUNT(*) OVER (PARTITION BY phone) AS cnt
  FROM users
) t WHERE t.cnt > 1;

-- 明细占组内份额:分子是当前行,分母是广播的组内合计
SELECT id, user_id, amount,
       ROUND(100 * amount / NULLIF(SUM(amount) OVER (PARTITION BY user_id), 0), 2) AS pct
FROM orders;

三种写法对比

需求写法说明
明细 + 组总数COUNT(*) OVER (PARTITION BY …)一条语句完成,不折叠行
只要组统计GROUP BY + COUNT(*)结果行数更少,内存占用更低
过滤组统计派生表 / CTE 包住窗口结果窗口函数不能出现在 WHERE
组内去重计数COUNT(DISTINCT x) OVER (…)PostgreSQL 支持,MySQL 8 不支持
窗口里用 COUNT(DISTINCT …) 的支持面很窄:PostgreSQL 支持,MySQL 8 会直接报错;需要在 MySQL 里做组内去重计数时,先用派生表去重,再在外面做窗口计数。
分区键含 NULL 时所有 NULL 行会被归入同一个分区(这一点与连接中「NULL 永不相等」的行为相反),用它检测重复会误报,需要先排除或统一空值。

易错点

  • 把窗口函数写进 WHERE 或 HAVING,直接语法报错
  • 写 COUNT(*) OVER () 时漏掉 PARTITION BY,得到全表行数而不是组内行数
  • 按含 NULL 的列分区做重复检测,NULL 行被归为同组,误报重复
  • 用窗口计数替代本可以用 GROUP BY 的统计,临时表与内存开销更大

数据来源与参考

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