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
相关产品推荐
相关产品推荐

