Laravel中如何在whereHas子查询中获取sum('count')?
问题
我有三个模型:Transaction、Cart、Acceptedcart。关联关系如下:
Cart包含transaction_id字段,Transaction与Cart是一对多关联:// Transaction.php public function carts() { return $this->hasMany(Cart::class); }Acceptedcart包含cart_id字段,Cart与Acceptedcart是一对多关联:// Cart.php public function accepted_carts() { return $this->hasMany(Acceptedcart::class); }
我已经实现了获取包含未发送(acceptedcart->sended == false)的 Acceptedcart 的 Transaction 查询:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) { $query->where('sended', false); })->get();
现在我想获取符合该条件的 Acceptedcart 中 count 列的总和,请问应该把 sum() 放在哪里?以下两种写法是否可行?
写法一:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) { $query->where('sended', false); })->sum('count');
写法二:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) { $query->where('sended', false)->sum('count'); })->get();
是否只能通过遍历 get() 结果的方式来实现?
回答
你给出的两种写法都不可行,原因如下:
- 写法一:
sum('count')是直接对transactions表的count字段求和,但你要的是关联的Acceptedcart表的count,表对应错误,结果肯定不符合预期。 - 写法二:
whereHas的闭包是用来筛选「存在符合条件的关联模型」的逻辑,在闭包里调用sum()会直接执行求和查询,破坏了原有的筛选逻辑,最终得到的$transactions不是你要的总和,而是不符合要求的模型集合。
不需要必须遍历结果,有更高效的实现方式:
方法一:直接从 Acceptedcart 模型查询(推荐)
既然目标是求和 Acceptedcart 的 count,且条件是该记录关联到 Transaction(对应你之前的 whereHas 逻辑),可以直接反向关联查询:
$totalCount = Acceptedcart::where('sended', false) ->whereHas('cart.transaction') // 确保该 Acceptedcart 关联到 Transaction ->sum('count');
需要先给 Acceptedcart 补充关联定义:
// Acceptedcart.php public function cart() { return $this->belongsTo(Cart::class); }
方法二:用 withSum 统计后汇总
如果你需要先拿到符合条件的 Transaction,再统计它们关联的 Acceptedcart 总和,可以用 Laravel 的 withSum 方法:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) { $query->where('sended', false); })->withSum(['carts.accepted_carts' => function ($query) { $query->where('sended', false); }], 'count')->get(); // 汇总所有 Transaction 对应的总和 $totalCount = $transactions->sum('carts_accepted_carts_sum_count');
方法三:遍历结果(仅适合小数据量)
就是你提到的遍历方式,适合数据量不大的场景:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) { $query->where('sended', false); })->with('carts.accepted_carts')->get(); $totalCount = 0; foreach ($transactions as $transaction) { foreach ($transaction->carts as $cart) { $totalCount += $cart->accepted_carts->where('sended', false)->sum('count'); } }
内容的提问来源于stack exchange,提问作者aref razavi
相关产品推荐
相关产品推荐

