Laravel按日期分组返回集合问题求助
问题描述
我编写了如下getOverdue函数,目前能正确返回所需数据,但尝试按RequiredTime字段分组时失败。RequiredTime字段为字符串类型,示例值:Jun 3 2024 05:00:00:000PM。我希望将结果按日期分组(忽略时间部分),比如120条结果分布在5个日期时,返回包含5个分组的集合。尝试过转换日期格式、使用DB::Raw()均触发SQL错误,恳请指点方向。
函数代码:
public function getOverdue() { $jobs = Job::where('RequiredTime', '<', Carbon::now()->addDays(10)->endOfDay()) ->where('JobCancelled', '=', 0) ->where('JobCompleted', '=', 0) ->where('Ref9', '=', null) ->where('CreateDateTime', '>=', Carbon::now()->startOfMonth()) //->groupBy('RequiredTime') ->orderBy('RequiredTime', 'asc') ->get(); return view('pages.dispatch.overdue', [ 'title' => 'Overdue', 'page' => 'Overdue', 'js_action' => 'dispatch|overdue', 'jobs' => $jobs ]); }
解决方案
针对字符串格式的日期字段分组,推荐两种可靠实现方式:
方式一:集合层面分组(简单不易出错)
先获取所有符合条件的数据,再利用Laravel集合的groupBy方法,将RequiredTime转换为日期格式后分组(忽略时间部分)。这种方式避开数据库层面的日期转换兼容性问题,代码更直观:
public function getOverdue() { $jobs = Job::where('RequiredTime', '<', Carbon::now()->addDays(10)->endOfDay()) ->where('JobCancelled', '=', 0) ->where('JobCompleted', '=', 0) ->where('Ref9', '=', null) ->where('CreateDateTime', '>=', Carbon::now()->startOfMonth()) ->orderBy('RequiredTime', 'asc') ->get() // 按日期分组:先把字符串转成Carbon实例,再提取纯日期部分 ->groupBy(function ($job) { return Carbon::parse($job->RequiredTime)->toDateString(); }); return view('pages.dispatch.overdue', [ 'title' => 'Overdue', 'page' => 'Overdue', 'js_action' => 'dispatch|overdue', 'jobs' => $jobs ]); }
方式二:数据库层面分组(性能更优,适合大数据量)
如果数据量较大,推荐在数据库层面完成日期转换和分组,需根据使用的数据库类型调整转换函数:
MySQL 版本
用STR_TO_DATE将字符串转为日期类型,再用DATE()提取日期部分分组:
use Illuminate\Support\Facades\DB; public function getOverdue() { $jobs = Job::select('*', DB::raw("DATE(STR_TO_DATE(RequiredTime, '%b %d %Y %h:%i:%s:%f%p')) as group_date")) ->where('RequiredTime', '<', Carbon::now()->addDays(10)->endOfDay()) ->where('JobCancelled', '=', 0) ->where('JobCompleted', '=', 0) ->where('Ref9', '=', null) ->where('CreateDateTime', '>=', Carbon::now()->startOfMonth()) ->groupBy('group_date') ->orderBy('group_date', 'asc') ->get(); return view('pages.dispatch.overdue', [ 'title' => 'Overdue', 'page' => 'Overdue', 'js_action' => 'dispatch|overdue', 'jobs' => $jobs ]); }
SQL Server 版本
用CONVERT和CAST完成格式转换:
use Illuminate\Support\Facades\DB; public function getOverdue() { $jobs = Job::select('*', DB::raw("CAST(CONVERT(datetime, RequiredTime, 100) AS date) as group_date")) ->where('RequiredTime', '<', Carbon::now()->addDays(10)->endOfDay()) ->where('JobCancelled', '=', 0) ->where('JobCompleted', '=', 0) ->where('Ref9', '=', null) ->where('CreateDateTime', '>=', Carbon::now()->startOfMonth()) ->groupBy('group_date') ->orderBy('group_date', 'asc') ->get(); return view('pages.dispatch.overdue', [ 'title' => 'Overdue', 'page' => 'Overdue', 'js_action' => 'dispatch|overdue', 'jobs' => $jobs ]); }
注意事项
- 方式一中,
Carbon::parse()可自动识别Jun 3 2024 05:00:00:000PM格式,无需额外指定格式符。 - 方式二中,日期转换的格式符需严格匹配字段存储格式,比如MySQL的
%b代表缩写月份(Jun),%p代表AM/PM。 - 若开启MySQL严格SQL模式,分组时需确保
SELECT中的非聚合字段都包含在GROUP BY中,或用聚合函数处理(如GROUP_CONCAT)。
内容的提问来源于stack exchange,提问作者fRAiLtY-
相关产品推荐
相关产品推荐

