Laravel Query Builder:如何对withSum()生成的字段进行计算?
解决Laravel中自关联模型父产品与子产品数量差值的计算问题
问题原因
你之前的写法无效,是因为withSum是Eloquent的关联预加载方法,它会单独执行查询计算子产品的数量总和,再把结果附加到模型实例上——这个别名ttl_children不是主查询的字段,所以无法在addSelect中直接引用。
解决方案
方案1:数据库层面直接计算(子查询方式)
通过子查询在主SQL中直接计算子产品总和与差值,适合大数据量场景:
use Illuminate\Support\Facades\DB; $products = Product::query() ->select([ '*', // 加载产品原有字段 // 计算子产品数量总和 DB::raw('(SELECT SUM(qty) FROM products WHERE parent_id = products.id) as sum_children'), // 计算剩余数量,用COALESCE处理无子女的情况(避免null值) DB::raw('qty - COALESCE((SELECT SUM(qty) FROM products WHERE parent_id = products.id), 0) as remaining') ]) ->whereNull('parent_id') // 可选:只查询父产品,根据需求调整 ->get();
方案2:集合层面处理(简洁易用)
先用withSum预加载子产品总和,再通过集合的map方法计算差值,代码更简洁,适合小数据量场景:
$products = Product::withSum('children as sum_children', 'qty') ->get() ->map(function ($product) { // 处理无子女的情况,默认总和为0 $product->remaining = $product->qty - ($product->sum_children ?? 0); return $product; });
方案3:关联Join+分组计算
通过自关联Join结合分组来计算总和与差值:
use Illuminate\Support\Facades\DB; $products = Product::query() ->leftJoin('products as children', 'products.id', '=', 'children.parent_id') ->select([ 'products.*', DB::raw('SUM(children.qty) as sum_children'), DB::raw('products.qty - COALESCE(SUM(children.qty), 0) as remaining') ]) ->groupBy('products.id') // 按父产品分组 ->get();
验证结果
以上三种方法都能得到你期望的结果:每个父产品模型会包含sum_children(子产品数量总和)和remaining(父产品数量减去子产品总和的差值)字段。
内容的提问来源于stack exchange,提问作者Hùng Thái
相关产品推荐
相关产品推荐

