Laravel中如何使用Eloquent关联改写按来源统计线索数的查询
Eloquent关联实现方案
前置配置:定义模型关联
使用Eloquent关联查询的前提是在模型中配置好表之间的关联关系,后续所有查询会自动读取关联配置的外键、主键映射,不需要手动编写连接条件。
在Customer模型中添加与线索表的一对多关联:
// app/Models/Customer.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Customer extends Model { // 其他已有配置... public function leads() { return $this->hasMany(Lead::class, 'customer_id', 'id'); } }
可选在Lead模型中添加反向归属关联(本次统计查询非必须,其他业务场景可复用):
// app/Models/Lead.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Lead extends Model { // 其他已有配置... public function customer() { return $this->belongsTo(Customer::class, 'customer_id', 'id'); } }
核心查询实现(全版本兼容,纯Eloquent关联逻辑)
使用Laravel自带的withCount关联聚合方法,结合分组求和实现统计,不需要手动编写任何join语句,和原有手写join查询逻辑100%等价,返回结构完全匹配需求:
// 传入实际的查询时间范围 $start_date = ''; $end_date = ''; $sourceLeadStats = Customer::withCount('leads') ->whereBetween('created_at', [$start_date, $end_date]) ->groupBy('source') ->selectRaw('source, sum(leads_count) as source_leads_count') ->orderBy('source_leads_count', 'DESC') ->get() ->toArray();
方案说明
- 关联逻辑完全依赖模型中定义的
leads()方法,后续如果外键、主键调整,只需要修改模型关联定义,不需要改动业务查询代码 - 兼容Laravel 5.3及以上所有版本,不需要引入额外扩展
- 避免了left join一对多表时产生的笛卡尔积行数膨胀问题,在
leads.customer_id加有索引的场景下,查询效率高于手写join - 完全符合
ONLY_FULL_GROUP_BY的SQL规范,不会出现SQL语法错误 - 返回结构和需求示例完全一致,示例返回如下:
[ [ "source" => "facebook", "source_leads_count" => 1300 ], [ "source" => "google", "source_leads_count" => 600 ] ]
可选:和原join逻辑生成完全相同SQL的写法(Laravel 9+)
如果需要生成和原有手写leftJoin完全一致的SQL,可以使用Laravel 9新增的leftJoinRelation方法,自动通过关联定义生成join语句,同样不需要手动编写外键连接条件:
$sourceLeadStats = Customer::select('customers.source') ->selectRaw('count(leads.id) as source_leads_count') ->leftJoinRelation('leads') ->whereBetween('customers.created_at', [$start_date, $end_date]) ->groupBy('customers.source') ->orderBy('source_leads_count', 'DESC') ->get() ->toArray();
内容的提问来源于stack exchange,提问作者AKT
相关产品推荐
相关产品推荐

