You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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-

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:31:17