这一公式组合在月度结账报告和边际贡献分析中极为常见:你手头有一张扁平的流水明细表,需要按自然月拆分统计,又不想新增辅助列,也不想导出数据透视表。
为什么 COUNTIF 不能直接接受 MONTH()
COUNTIF 的第一参数要求的是区域引用--即 C2:C3001 这样具体的单元格块。如果直接传入 MONTH(C2:C3001) 而不加 ARRAYFORMULA,Google Sheets 只会对区域中的第一个单元格执行 MONTH 运算,返回一个单一整数(第2行日期对应的月份),而非数组。最终 COUNTIF 的结果只会是1或0,取决于这一个日期是否符合条件。
ARRAYFORMULA 强制让 MONTH 在整个区域上完成运算,再将结果交给 COUNTIF。此时 COUNTIF 接收到的是一个包含1到12的整数内存数组,匹配逻辑得以正常执行。
用 COUNTIF + ARRAYFORMULA(MONTH()) 生成12个月统计值
单月统计:
=COUNTIF(ARRAYFORMULA(MONTH(Transactions!C2:C3001)), 3)
管理层汇报摘要行(B4:M4 存放月份数字1到12):
=COUNTIF(ARRAYFORMULA(MONTH(Transactions!$C$2:$C$3001)), B4)
将公式向右拖拽至 M4,每个单元格自动读取表头行的月份数字并统计对应行数。3,000行数据全部12个月重新计算,通常在一秒内完成。
如果希望用单个公式一次性输出12个月数据、无需拖拽,COUNTIF 本身不支持条件区域的批量迭代。可使用 MAP 配合 LAMBDA(Google Sheets 于2023年第四季度正式面向所有用户推出,详见 Google Workspace 更新日志):
=MAP(ROW(INDIRECT("1:12")), LAMBDA(m,
COUNTIF(ARRAYFORMULA(MONTH(Transactions!$C$2:$C$3001)), m)
))
此公式向下溢出12个值。如果汇总行是横向排列,用 TRANSPOSE 转置即可。若需兼容2023年以前的旧版本,直接拖拽单月公式也可--逻辑更直观,CFO追问公式来源时也更易说明。
修复 COUNTIF ARRAYFORMULA MONTH 公式的空单元格 Bug
这个问题会悄无声息地污染1月份数据,在所有使用开放式区域的财务模型中普遍存在。
MONTH("") 返回1。日期列中每一个空白单元格都会被计入1月。假设你有一个3,000行的区域,其中2,000行暂时为空(当前处于 FY2026 年第一季度,数据仅录入至3月),那么1月的统计值将被虚增2,000。
用 COUNTIFS 修复:
=COUNTIFS(
ARRAYFORMULA(MONTH(Transactions!C2:C3001)), 3,
Transactions!C2:C3001, "<>"
)
第二个条件在月份匹配前先排除空白日期。拖拽至12个月时同样适用--锁定区域引用,将硬编码的 3 替换为表头月份单元格引用即可。
也可以在 ARRAYFORMULA 内部直接屏蔽空单元格:
=COUNTIF(
ARRAYFORMULA(IF(Transactions!C2:C3001<>"", MONTH(Transactions!C2:C3001), "")),
3
)
两种写法均有效。COUNTIFS 版本将"排除空值"的逻辑显式呈现,便于审计--尤其是在排查1月差异时,追溯逻辑更为清晰。
何时切换到 SUMPRODUCT
SUMPRODUCT 在一次运算中同时处理空单元格过滤和月份提取,无需中间的 ARRAYFORMULA 层:
=SUMPRODUCT(
(MONTH(Transactions!$C$2:$C$3001)=3) *
(Transactions!$C$2:$C$3001<>"")
)
在数据量不超过1万行时,两种方案性能相当。超过5万行后,SUMPRODUCT 的重新计算速度通常更快,因为它无需生成中间数组。根据 Google Sheets 帮助中心文档《Google 表格中的 Google 表格大小限制》,电子表格上限为1000万个单元格--在大规模交易日志场景下,SUMPRODUCT 可比等效的 COUNTIF+ARRAYFORMULA 公式快2至3倍。
按月汇总金额(而非计数):
=SUMPRODUCT(
(MONTH(Transactions!$C$2:$C$3001)=3) *
(Transactions!$C$2:$C$3001<>"") *
Transactions!$D$2:$D$3001
)
其中D列为交易金额。财务规划与分析(FP&A)工作中,按月汇总收入通常才是核心需求--行数统计更多作为对金额汇总的合理性校验。
| 方案 | 空单元格安全? | 多月溢出? | 适用场景 |
|---|---|---|---|
COUNTIF(ARRAYFORMULA(MONTH())) | 否(需改用 COUNTIFS) | 配合 MAP/LAMBDA 可实现 | 交易计数,1万行以内 |
COUNTIFS(ARRAYFORMULA(MONTH()), ..., range, "<>") | 是 | 否(拖拽或 MAP) | 需审计的月度计数 |
SUMPRODUCT((MONTH()=m)*(range<>"")) | 是 | 否(拖拽) | 计数或求和,任意数据量 |
MAP(ROW(INDIRECT("1:12")), LAMBDA(m, COUNTIF(...))) | 取决于内层公式 | 是 | 管理层汇报12个月溢出输出 |
嵌入多标签页财务模型
在季度管理层汇报材料中,月度统计值通常汇聚到汇总标签页,再由其他标签页引用。一套清晰的架构如下:
Transactions 标签页(原始数据):C列为日期,D列为金额,E列为 SKU 或科目分类。
Monthly Summary 标签页:B5:B16 存放月份数字1到12,公式如下:
=COUNTIFS(
ARRAYFORMULA(MONTH(Transactions!$C$2:$C$3001)), $B5,
Transactions!$C$2:$C$3001, "<>",
Transactions!$E$2:$E$3001, '利润表'!$C$2
)
此公式统计 $B5 月份中,科目分类与利润表假设单元格匹配的交易行数。利润表标签页再通过以下公式汇总:
=SUMIFS('Monthly Summary'!D:D, 'Monthly Summary'!B:B, ">=" & Assumptions!$B$3)
两层标签页引用,全部锁定,无辅助列。修改任意一笔交易的日期,利润表数据即时联动更新。审计链路从原始数据到月度汇总再到利润表,全程透明,没有任何内容隐藏在数据透视缓存中。
常见问题
Q:COUNTIF(ARRAYFORMULA(MONTH())) 与直接 COUNTIF(MONTH()) 有何区别?
直接写 COUNTIF(MONTH(C2:C3001), 3) 时,MONTH 仅对区域首行求值并返回单一数字,COUNTIF 匹配的始终是同一个值,结果非0即1。加上 ARRAYFORMULA 后,MONTH 对整列逐行求值,COUNTIF 拿到完整的月份数组,才能正确累计计数。
Q:为什么1月的统计数字异常偏高?
空白日期单元格会被 MONTH("") 解析为1,自动计入1月。只需在 COUNTIFS 中加入第二个条件 Transactions!C2:C3001, "<>" 即可排除空值,详见上文"修复空单元格 Bug"章节。
Q:数据超过5万行时该用哪个公式?
优先选用 SUMPRODUCT。它在内部以向量运算处理所有条件,不产生 ARRAYFORMULA 所需的中间数组,在大规模数据集上重新计算速度更快,同时天然支持空值过滤。
Q:能否同时按月份和科目类别统计?
可以,切换为 COUNTIFS 并追加第三个条件对即可,例如 Transactions!$E$2:$E$3001, "收入" --无需修改 ARRAYFORMULA(MONTH()) 部分的逻辑。
Q:MAP + LAMBDA 方案对 Google Sheets 版本有要求吗?
MAP 和 LAMBDA 函数于2023年第四季度向所有 Google Workspace 用户全量开放(参见 Google Workspace 更新日志)。如果你的表格所在组织尚未升级,或需与外部协作方共享兼容性更强的文件,建议改用拖拽单月公式方案。
查看 ModelMonkey 方案--支持 Google Sheets 和 Excel。