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

Laravel/MySQL:筛选关联模型最高版本且非草稿状态的最新记录

解决方案

1. 定义正确的hasOne关联

在Contract模型中修改latestVersion关联,通过子查询锁定每个合约对应的最高版本记录,同时排除status为draft的情况:

public function latestVersion()
{
    return $this->hasOne(ContractVersion::class, 'contract_id')
        // 子查询获取当前合约的最高版本号
        ->whereRaw('version = (SELECT MAX(version) FROM contract_versions WHERE contract_id = ?)', [$this->id])
        // 排除草稿状态的记录
        ->where('status', '!=', 'draft');
}

2. 执行查询并过滤无效父记录

使用has('latestVersion')确保只返回存在符合条件关联记录的父合约,再结合with('latestVersion')加载关联数据并分页:

$contracts = Contract::with('latestVersion')
    ->has('latestVersion') // 过滤掉没有有效最新版本的合约
    ->paginate();

为什么之前的方法无效?

  • latest()仅对结果集排序,无法保证只取每个合约的最高版本记录;
  • groupBy('version')是按版本号分组,而非按合约ID分组,不符合需求逻辑。

替代写法(子查询关联)

如果需要更清晰的关联逻辑,也可以在查询时直接指定关联条件:

$contracts = Contract::with(['latestVersion' => function ($query) {
    $query->whereRaw('version = (SELECT MAX(version) FROM contract_versions WHERE contract_id = contracts.id)')
          ->where('status', '!=', 'draft');
}])
->has('latestVersion')
->paginate();

基于Join的实现方式

如果需要更高性能,可以通过子查询预取每个合约的最高版本,再通过Join关联筛选:

// 先获取每个合约的最高版本号
$maxVersions = ContractVersion::select('contract_id', DB::raw('MAX(version) as max_version'))
    ->groupBy('contract_id');

// 关联查询并筛选有效记录
$contracts = Contract::joinSub($maxVersions, 'max_versions', function ($join) {
    $join->on('contracts.id', '=', 'max_versions.contract_id');
})->join('contract_versions', function ($join) {
    $join->on('contracts.id', '=', 'contract_versions.contract_id')
         ->on('contract_versions.version', '=', 'max_versions.max_version');
})->where('contract_versions.status', '!=', 'draft')
  ->select('contracts.*') // 只选择合约表字段
  ->with('latestVersion') // 按需加载关联模型
  ->paginate();

内容的提问来源于stack exchange,提问作者Eugen Stranz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 15:05:03