ERP接口月度统计少了零单月份:SQLite分组与最近三个月均值排查

ERP对接月报只显示8月和10月,9月没有单据,最近三个月平均值却和这两个月的均值相同。这时先查统计SQL是否只返回"存在记录的月份"。

本文依据实际SQLite统计函数,用构造推送记录复现空月份缺失。样本数量只用于解释计算口径,不代表客户单量、收入或真实收费结果,也没有查询任何真实账套。

1. GROUP BY 不会自动生成没有记录的月份

当前月度统计按连接过滤推送记录,只统计状态为 done 的行,核心SQL如下:

sql 复制代码
SELECT strftime(
         '%Y-%m',
         datetime(updated_at / 1000, 'unixepoch', '+8 hours')
       ) AS ym,
       doc_type, COUNT(*) AS n
FROM push_records
WHERE conn_id = ? AND state = 'done'
GROUP BY ym, doc_type
ORDER BY ym DESC;

月份由记录的 updated_at 计算,按代码中的UTC加8小时归月;不是按来源单据的业务日期归月。一个月没有满足条件的行,就没有该月分组。

查询之后,代码按月份合并不同单据类型的数量,再对结果执行 slice(0, months)。因此这里的 months 限制的是"返回多少个有记录的月份",没有创建连续的自然月区间。

2. 最近三个月为什么只用了两个数

在内存数据库中构造12条 done 记录:2026年8月6条,10月6条,9月0条。单据号和连接标识全部为演示值,调用实际 monthlyCounts(..., { months: 3 }) 得到:

json 复制代码
[
  {"ym":"2026-10","total":6},
  {"ym":"2026-08","total":6}
]

这里展示月份和总量,实际返回还包含按单据类型汇总的 byType。随后平均值函数执行:

javascript 复制代码
const take = list.slice(0, months);
if (!take.length) return 0;
return Math.round(
  take.reduce((s, m) => s + m.total, 0) / take.length
);

它使用实际取到的列表长度作分母。本次得到 (6 + 6) / 2 = 6,而不是把9月补0后的 (6 + 0 + 6) / 3 = 4。

图1:内存数据库构造数据;9月为0是本例已知条件,不是对生产缺失月份的推断。

这不是SQLite把0算错了,而是输入给平均函数的列表根本没有9月。

3. 先决定月报要表达哪一种口径

"最近三个有业务的月份"和"截至某月的连续三个月"都可以是有效指标,但含义不同。若页面或合同写连续自然月,就不能仅截取三个分组充当实现。

还要明确是否包含本月。本月尚未结束,和前两个月直接比较可能造成误读;应约定统计截止日,或者只取完整自然月。

对新接入的连接,也要明确启用前的月份如何处理。没有接入、没有完整采集和确实没有业务,不能一概记成0。

本地构造证明了分母差异,没有证明任何客户应使用哪个口径。实际验收应先把这些定义写清,再检查代码与页面说明是否一致。

4. 需要连续月份时,先建立月份序列

一种建议做法是先固定统计截止月,再生成连续月份,随后按月份合并聚合结果。下面的独立片段只演示合并,月份序列是手工给定的构造值:

javascript 复制代码
const months = ['2026-10', '2026-09', '2026-08'];
const counts = new Map([
  ['2026-10', 6],
  ['2026-08', 6]
]);
const filled = months.map(ym => ({
  ym,
  total: counts.get(ym) ?? 0
}));

本例已知9月没有业务,因此可以补0,再交给平均函数计算,得到4。生产使用时应先验证该月的采集完整性;未知或采集失败可以单独标记,不能静默补0并宣称准确月均。

该建议没有修改当前统计实现,也没有实现通用月份生成器。跨年、月末、闰年及不同统计窗口,还需要单独验证。

5. 月份补齐后,记录归属也要核对

当前SQL同时依赖记录的现有状态和 updated_at。它统计的是此刻满足 done 条件的记录,不是不可变的成功事件流水;后续状态或时间字段变更可能改变重新查询的结果。

如果业务要求历史月报在结账后保持稳定,应考虑独立成功时间、状态事件或已经确认的月度快照。这些是设计方向,没有在本次实现或验证为完整报表方案。

验收时建议同时覆盖:中间月为0、所有月为0、只有一个月、跨年窗口、新连接启用月,以及记录时间和单据业务日期跨月。展示数量、平均分母和截止时间,让读者能还原计算过程。

本次实际验证了两个事实:没有记录的月份不出现在当前分组结果中,平均函数按返回列表长度计算。连续自然月补0后的4是本地演示对照值,不能替代真实业务的完整性核实。

相关推荐
David猪大卫1 小时前
【C++修炼】STL容器—stack与queue
c语言·开发语言·数据结构·c++·经验分享·笔记·学习
ClouGence1 小时前
支付机构为什么需要数据同步:从监管报送到跨云业务协作
数据库·数据分析
德思特1 小时前
弱网测试入门:为什么你的设备在电梯里会断网?
经验分享·弱网测试
wuyk5551 小时前
PyQt6-第14讲-数据库与Excel双向同步
数据库·python·ui·excel·pyqt
mONESY1 小时前
从线性 RAG 到 Agentic RAG|基于 LangGraph 实现自主决策 RAG 闭环
javascript·面试
我的xiaodoujiao1 小时前
Django 权限系统项目实战详细图文教程 3--系统登录功能实现
后端·python·django
可乐_不渴1 小时前
【Linux】 进程虚拟地址空间
java·linux·javascript
SimonKing1 小时前
号外号外,Stream-Nexus推送项目支持集群部署了
java·后端·程序员
老王IT1 小时前
Rust开发环境搭建教程
开发语言·后端·rust