
本文介绍在 codeigniter 中按月统计数据库记录时,如何自动补全 1–12 月中未出现的月份,并将其计数设为 0,确保结果数组包含完整月份序列。
本文介绍在 codeigniter 中按月统计数据库记录时,如何自动补全 1–12 月中未出现的月份,并将其计数设为 0,确保结果数组包含完整月份序列。
在使用 CodeIgniter 进行按月分组统计(如 GROUP BY MONTH(created_at))时,SQL 查询默认只返回数据库中实际存在的月份数据,导致结果中缺失的月份(如 1 月、3 月等)完全不出现。但业务场景常要求返回连续的 12 个月结构化数据,缺失月份需显式填充为 {"count": 0, "month": N}。仅靠 SQL 很难优雅实现(尤其跨年时),推荐采用「查询 + PHP 补全」的组合方案。
以下是优化后的完整实现逻辑(兼容 CodeIgniter 4 的 Query Builder):
// 构建查询:注意修正原代码中的 GROUP BY 逻辑(YEAR+MONTH 才能准确定位单月)
$result = $builder->select('COUNT(insta_alert_id) as count, MONTH(created_at) as month')
->where("created_at BETWEEN '2022-04-01' AND '2023-07-31'")
->where('school_id', $loginDt['school_id'])
->groupBy('YEAR(created_at)', 'MONTH(created_at)') // ✅ 关键:同时按年月分组,避免跨年混淆
->get()
->getResultArray();
// 初始化标准月份映射(1~12)
$data = array_fill_keys(range(1, 12), ['count' => 0, 'month' => null]);
// 填充已存在的月份数据
foreach ($result as $row) {
$month = (int)$row['month'];
if ($month >= 1 && $month (int)$row['count'],
'month' => $month
];
}
}
// 转为有序索引数组(保证 1→12 顺序)
$data = array_values($data);
✅ 关键改进点说明:
- 使用
array_fill_keys(range(1,12), ...)预置完整月份骨架,避免循环判断; -
GROUP BY YEAR(created_at), MONTH(created_at)确保跨年数据不被错误合并(如 2022-12 和 2023-12 不会归为同一组); - 显式类型转换
(int)防止字符串比较异常; - 最终
array_values()保证输出为严格升序的索引数组,符合前端预期。
⚠️ 注意事项:
- 若需支持动态时间范围(如用户选择 2023-01 至 2023-06),应将
range(1,12)替换为range((int)date('n', strtotime($start)), (int)date('n', strtotime($end))),并处理跨年逻辑; - 数据库字段
created_at必须为DATETIME或TIMESTAMP类型,否则MONTH()函数可能返回NULL; - 如统计量极大,可考虑在数据库层用
LEFT JOIN临时月份表(需额外维护),但 PHP 补全在中小项目中更简洁可控。
通过该方案,你将稳定获得包含全部 12 个月(或指定区间月份)的结构化响应,无需前端二次处理,大幅提升图表渲染与报表生成的可靠性。











