
本文详解 CodeIgniter 中按年月精确筛选数据库记录时 like() 方法失效的原因,并提供使用 DATE_FORMAT() 的正确 SQL 条件写法,确保按指定年月(如 '2022-01')完整匹配所有当月数据。
本文详解 codeigniter 中按年月精确筛选数据库记录时 `like()` 方法失效的原因,并提供使用 `date_format()` 的正确 sql 条件写法,确保按指定年月(如 '2022-01')完整匹配所有当月数据。
在 CodeIgniter 中,使用 $this->db->like('date', $stotal) 进行日期模糊匹配看似简洁,实则存在根本性缺陷:LIKE 是字符串通配操作,而 MySQL 的 date 字段(通常为 DATE 或 DATETIME 类型)在底层以 YYYY-MM-DD HH:MM:SS 格式存储。当传入 $stotal = '2022-01' 时,like '2022-01%' 可能意外匹配到 2022-01-01、2022-01-15 等,但更严重的问题是——若 date 字段包含时间部分(如 2022-01-15 14:30:22),且数据库字符集或排序规则导致隐式类型转换异常,LIKE 可能完全失效或返回空结果。此外,LIKE 无法保证语义上的“整月匹配”,易受前导/尾随空格、时区、格式差异影响。
✅ 正确做法是使用 MySQL 原生日期函数进行结构化匹配。推荐使用 DATE_FORMAT() 将日期字段标准化为 'YYYY-MM' 格式后精确比对:
public function searchbilling($stotal) {
$this->db->select('*, SUM(quantity) as quantity');
$this->db->from('delivered');
// ✅ 使用 DATE_FORMAT 精确提取年月并等值匹配
$this->db->where("DATE_FORMAT(date, '%Y-%m') =", $stotal);
$this->db->group_by('YEAR(date), MONTH(date), customer');
$query = $this->db->get();
return $query->result();
}
⚠️ 注意事项:
- 字段类型确认:确保 delivered.date 字段为 DATE、DATETIME 或 TIMESTAMP 类型;若为 VARCHAR 存储日期,请先用 STR_TO_DATE() 转换,否则 DATE_FORMAT() 无效。
-
SQL 注入防护:$stotal 由前端下拉框固定生成(如 '2022-01'),本身无用户自由输入,但仍建议增加校验:
if (!preg_match('/^\d{4}-\d{2}$/', $stotal)) { return []; } -
性能优化:DATE_FORMAT(date, '%Y-%m') 无法利用 date 字段上的索引。如查询频繁,建议添加生成列索引(MySQL 5.7+):
ALTER TABLE delivered ADD COLUMN date_ym CHAR(7) AS (DATE_FORMAT(date, '%Y-%m')) STORED; CREATE INDEX idx_date_ym ON delivered(date_ym);
对应模型中可改用 $this->db->where('date_ym', $stotal) 提升效率。
-
兼容性替代方案:若需跨数据库兼容(如适配 PostgreSQL),可改用范围查询:
$start = $stotal . '-01'; $end = date('Y-m-t', strtotime($stotal . '-01')); // 当月最后一天 $this->db->where('date >=', $start); $this->db->where('date
总结:日期搜索务必避免 like() 字符串匹配,优先采用数据库原生日期函数(DATE_FORMAT / YEAR() / MONTH())或时间范围条件。本方案既保证结果完整性,又符合 CodeIgniter 查询构建器规范,是生产环境推荐实践。











