Laravel中如何让withAggregate关联查询按指定顺序排序?
解决Laravel
withAggregate忽略关联排序的问题 问题场景
使用withAggregate做关联聚合查询时,即便在HasOne关联里定义了orderBy规则,生成的子查询依然不会带上排序,导致只能拿到关联表的最早记录。
原查询代码:
$users = \App\Models\User::withAggregate('lastactivity', 'created_at') ->orderBy('id', 'DESC') ->paginate(15);
生成的SQL(缺少关联排序):
select `users`.*, (select created_at from `users_activity` where `users`.`id` = `users_activity`.`user_id` limit 1) as `lastactivity_created_at` from `users` order by `id` desc limit 15 offset 0
期望生成的SQL(包含关联降序排序):
select `users`.*, (select created_at from `users_activity` where `users`.`id` = `users_activity`.`user_id` order by id desc limit 1) as `lastactivity_created_at` from `users` order by `id` desc limit 15 offset 0
关联关系定义:
public function lastactivity(): HasOne { return $this->hasOne(UsersActivity::class)->orderBy('id', 'DESC'); }
解决方法
直接在withAggregate中传入闭包,手动指定子查询的排序规则:
$users = \App\Models\User::withAggregate('lastactivity', function ($query) { $query->select('created_at')->orderBy('id', 'DESC'); })->orderBy('id', 'DESC')->paginate(15);
原因说明
withAggregate在构建聚合子查询时,不会完全复用关联定义里的所有约束(比如排序),而是会生成一个简化的查询实例。因此必须通过闭包显式传入排序规则,才能确保子查询按要求获取最新的关联记录。
复用优化方案
如果需要在多处使用这个逻辑,可以在模型里单独定义一个带排序的聚合关联方法:
public function latestActivity() { return $this->hasOne(UsersActivity::class) ->select('user_id', 'created_at') ->orderBy('id', 'DESC'); }
之后调用withAggregate时直接用这个方法:
$users = \App\Models\User::withAggregate('latestActivity', 'created_at') ->orderBy('id', 'DESC') ->paginate(15);
内容的提问来源于stack exchange,提问作者Linesofcode
相关产品推荐
相关产品推荐

