
当 codeigniter 3 查询无匹配记录时,`row()->sold_price` 会触发 php 致命错误(因访问 null 对象属性),而非返回 0 或 null;根本原因是链式调用缺乏空值保护,且 `where()` 多参数误用导致 sql 条件拼接错误。
在 CodeIgniter 3 中,$this->db->where() 方法不支持单次调用传入多个条件字段(如你原代码中 ->where(‘category_ID’, $caid,’sold_date >=’,$prev_year_start_month,…))。这种写法会导致 CI 忽略后续参数,仅执行第一个 where(‘category_ID’, $caid),其余日期条件被丢弃——这正是查询“跨年拉取数据”的根源:缺少日期过滤,数据库返回了其他年份的任意匹配记录。
✅ 正确做法是将每个 WHERE 条件拆分为独立的 where() 调用,或使用字符串形式的复合条件:
// ✅ 推荐:清晰、安全、符合 CI 最佳实践
$query = $this->db->select_sum('sold_price')
->from('tbl_sales')
->where('category_ID', $caid)
->where('sold_date >=', $prev_year_start_month)
->where('sold_date <=', $prev_year_end_month)
->group_by('category_ID')
->get();
$result = $query->row();
$sold_price = ($result && isset($result->sold_price)) ? (float)$result->sold_price : 0.0;
⚠️ 注意事项:
- 永远不要直接调用 ->row()->xxx:若查询无结果,row() 返回 null,再访问 ->sold_price 将抛出 Trying to get property ‘sold_price’ of non-object 错误;
- 使用 isset() 或三元判断确保对象存在;
- 日期字段(如 sold_date)需确保数据库中为 DATE 或 DATETIME 类型,且 $prev_year_start_month、$prev_year_end_month 格式为 ‘Y-m-d’(如 ‘2023-01-01’),避免隐式类型转换;
- 若需兼容无分组场景(如单条记录),可改用 ->row_array() + array_key_exists() 增强健壮性;
- 避免拼接 SQL 字符串(如第二种答案中的 “category_ID= $caid AND…”),易引发 SQL 注入,除非 $caid 和日期变量已严格过滤(强烈不推荐)。
? 进阶建议:封装为可复用方法,自动处理空值与类型转换:
protected function getSumByDateRange($table, $sum_field, $where_conditions = [], $date_field = 'sold_date', $start = '', $end = '') {
$this->db->select_sum($sum_field);
$this->db->from($table);
foreach ($where_conditions as $key => $value) {
$this->db->where($key, $value);
}
if (!empty($start) && !empty($end)) {
$this->db->where("{$date_field} >= ", $start);
$this->db->where("{$date_field} <= ", $end);
}
$row = $this->db->get()->row();
return $row ? (float)($row->$sum_field ?? 0) : 0.0;
}
// 调用示例
$total = $this->getSumByDateRange(
'tbl_sales',
'sold_price',
['category_ID' => $caid],
'sold_date',
$prev_year_start_month,
$prev_year_end_month
);
通过规范 where() 用法 + 主动判空,即可彻底解决“本该返回 0 却报错或返回错误数据”的问题,保障查询逻辑的准确性和系统稳定性。
