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

Laravel Eloquent:基于最新HasMany关联筛选数据

嘿,我看你已经把Lead和LeadStatus的关联都配置好了,现在要筛选出最新状态符合特定值的Lead对吧?这里有几个靠谱的方案,你可以根据自己的场景选择:

方案一:借助已有的activeStatus关联(最简洁)

你已经定义了activeStatus这个hasOne关联,它会自动取每个Lead的最新LeadStatus记录,直接用whereHas就能筛选:

// 替换成你要筛选的状态值,比如'qualified'/'contacted'
$targetStatus = 'qualified';

$filteredLeads = Lead::whereHas('activeStatus', function ($query) use ($targetStatus) {
    $query->where('status', $targetStatus);
})->get();

这个方法最贴合你现有的代码结构,可读性也很强,日常用完全没问题。

方案二:子查询获取最新状态ID(性能更优)

如果你的数据量比较大,用子查询先锁定每个Lead的最新状态记录,再关联筛选会更高效:

$targetStatus = 'qualified';

// 先子查询找出每个lead对应的最新LeadStatus的ID
$latestStatusIds = LeadStatus::select(DB::raw('MAX(id) as id'))
    ->groupBy('lead_id');

$filteredLeads = Lead::whereHas('statuses', function ($query) use ($latestStatusIds, $targetStatus) {
    $query->whereIn('id', $latestStatusIds)
          ->where('status', $targetStatus);
})->get();

这里用MAX(id)是因为自增ID通常和created_at递增一致,比排序created_at更快,如果你的created_at是唯一且严格递增的,也可以换成基于created_at的子查询。

方案三:原生JOIN写法

如果你习惯用SQL的JOIN思路,也可以这么实现:

$targetStatus = 'qualified';

$filteredLeads = Lead::join(
    // 子查询生成每个Lead的最新状态临时表
    DB::raw('(SELECT lead_id, status FROM lead_statuses ORDER BY created_at DESC GROUP BY lead_id) AS latest_statuses'),
    'leads.id',
    '=',
    'latest_statuses.lead_id'
)->where('latest_statuses.status', $targetStatus)
->select('leads.*') // 只选择Lead表的字段,避免字段冲突
->get();

小提醒

  • 记得给lead_statuses表的lead_id和created_at字段加索引,能大幅提升这些查询的速度
  • 如果你的业务里允许同一Lead在同一时间有多个状态记录,那最好用MAX(id)来判断最新,而不是created_at

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:57:29