Laravel分组后求和报错:Call to a member function sum() on string
解决Laravel中GroupBy后求和触发的"Call to a member function sum() on string"错误
嘿,我一眼就看出你代码里的问题啦!你在groupBy的回调里犯了个逻辑错误——Carbon::parse($date->created_at)->format('W,M,Y')返回的是字符串类型的日期(比如"32,Aug,2024"),你居然直接在这个字符串上调用sum('price'),这不触发"Call to a member function sum() on string"错误才怪呢!
错误根源拆解
你的代码逻辑搞反了:groupBy的回调只需要返回分组的标识(键),而不是直接在回调里做求和操作。求和应该是分组完成后,对每个分组集合进行的操作。
解决方案1:集合层面分组求和(适合小数据量)
先把符合条件的数据查出来,再按格式化后的日期分组,最后对每个分组的price字段求和:
// 注意模型名要大写,Laravel规范是首字母大写的模型类 $invoices = Invoice::where('instructor_id', '=', $id)->get(); $groupedData = $invoices->groupBy(function($invoice) { // 这里只返回分组的键:格式化后的日期字符串 return Carbon::parse($invoice->created_at)->format('W,M,Y'); })->map(function($group) { // 对每个分组里的所有记录,求和price字段 return $group->sum('price'); });
这样$groupedData里就会是类似["32,Aug,2024" => 1500, "33,Aug,2024" => 2200]的键值对,键是格式化后的日期,值是对应分组的总价。
解决方案2:数据库层面分组求和(推荐,大数据量更高效)
如果你的数据量比较大,把所有数据拉到内存里再处理会很影响性能,直接让数据库帮你完成分组和求和操作更靠谱:
// MySQL版本:用DATE_FORMAT格式化日期,和Carbon的W,M,Y对应 $groupedData = Invoice::where('instructor_id', '=', $id) ->selectRaw('DATE_FORMAT(created_at, "%v,%b,%Y") as date_group, SUM(price) as total_price') ->groupBy('date_group') ->get(); // 如果你用的是PostgreSQL,把DATE_FORMAT换成TO_CHAR: // ->selectRaw('TO_CHAR(created_at, \'WW,Mon,YYYY\') as date_group, SUM(price) as total_price')
这种方式下,数据库会直接返回分组后的结果集合,每个元素包含date_group(格式化后的日期)和total_price(对应分组的总价),性能比集合处理高很多。
额外注意点
- 模型名要遵循Laravel规范:首字母大写(
Invoice而非invoice),避免类找不到的错误; - 确保
created_at字段是日期/时间类型,Carbon能正确解析; - 不同数据库的日期格式化函数有差异,比如MySQL用
DATE_FORMAT,PostgreSQL用TO_CHAR,SQL Server用FORMAT,要根据你的数据库类型调整。
内容的提问来源于stack exchange,提问作者user379888
相关产品推荐
相关产品推荐

