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

Laravel 8 中如何实现一对多关联按子表result_part_id分组取最新记录

环境与前提

使用开启了strict=true SQL模式的Laravel 8 + MySQL 8开发环境,涉及两张数据表结构如下:

exam_results
    id, result_date

examresult_revisions
    id, examresult_id, result_part_id, revision_id, created_at, updated_at ... 

已定义的模型关联:

class Examresult extends Model
{
    public function revisions()
    {
        return $this->hasMany(ExamresultRevision::class);
    }
}
需求

每个考试结果(ExamResult)包含多个对应不同result_part_id的部分,每个部分可能存在多个修订版本,需要为每个ExamResult获取按result_part_id分组的最新ExamresultRevision记录。

实现方案

方案1:使用MySQL 8窗口函数(推荐,性能最优)

ROW_NUMBER()窗口函数天然适合分组取TopN的场景,完全兼容严格模式:

// 单个ExamResult加载最新分部分修订
$examResult = Examresult::with(['revisions' => function ($query) {
    $query->selectRaw('*, ROW_NUMBER() OVER (PARTITION BY result_part_id ORDER BY created_at DESC, id DESC) as rn')
          ->having('rn', '=', 1);
}])->find($examResultId);

// 批量加载多个ExamResult的最新分部分修订也可直接使用该写法,无N+1问题

说明:ORDER BY追加id DESC是为了处理同一部分同一时间提交多条修订的极端情况,取自增ID更大的记录作为最新版本,逻辑更稳妥。

方案2:子查询匹配最新记录ID

如果不想使用窗口函数,可以用子查询匹配每个部分的最新修订ID,同样符合严格模式要求:

$examResult = Examresult::with(['revisions' => function ($query) {
    $latestRevisionIds = ExamresultRevision::selectRaw('MAX(id) as id')
        ->whereColumn('examresult_id', 'examresult_revisions.examresult_id')
        ->groupBy('result_part_id');

    $query->whereIn('id', $latestRevisionIds);
}])->find($examResultId);

方案3:封装为独立关联(Laravel 8.42+版本支持)

可以借助Laravel内置的ofMany方法封装为专属关联,后续调用更简洁:

// 在Examresult模型中新增关联方法
public function latestRevisionPerPart()
{
    return $this->hasMany(ExamresultRevision::class)
        ->ofMany('id', 'max') // 按自增ID最大判定为最新,也可替换为 'created_at', 'max' 按创建时间判断
        ->groupBy('result_part_id');
}

// 调用时直接预加载即可
$examResult = Examresult::with('latestRevisionPerPart')->find($examResultId);
注意事项
  • 以上所有写法都不会触发严格模式下的ONLY_FULL_GROUP_BY报错
  • 数据量较大时优先选择窗口函数方案,查询效率更高
  • 如果修订存在软删除,对应查询需要追加->withoutTrashed()过滤已删除记录

内容的提问来源于stack exchange,提问作者Saleem Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:15:03