Laravel关联3张表求和时佣金总额计算错误问题排查
关联多表时佣金总额计算错误的原因及解决方法
问题原因
当同时对order_items和commissions做左连接时,会产生笛卡尔积:
- 假设一个订单对应
N条order_items记录、M条commissions记录,关联后会生成N*M条重复组合的记录。 - 你的案例里,每个订单的
commissions记录被重复计算了N次(N是该订单的商品条目数),最终SUM(sc.amount)的结果是实际佣金总额的多倍,所以才会从259.88涨到1649.56。 - 而
totalamount结果正确,是因为SUM(oi.qty * oi.each)统计的是每个商品条目的金额,即使关联后每条商品记录附带了佣金信息,商品条目本身并没有被重复,加总后和单独统计的结果一致。
解决方法
要避免笛卡尔积,可通过以下几种方式处理:
方法1:分开查询再合并(最简单直观)
分别统计两个总额后组合结果:
// 统计佣金总额 $commissionStats = Order::select(DB::raw('SUM(sc.amount) as totalcommissions')) ->leftJoin('commissions as sc', 'sc.order_id', '=', 'orders.id') ->first(); // 统计订单总金额 $amountStats = Order::select(DB::raw('SUM(oi.qty * oi.each) as totalamount')) ->leftJoin('order_items as oi', 'oi.order_id', '=', 'orders.id') ->first(); // 组合最终结果 $getstats = [ 'totalcommissions' => $commissionStats->totalcommissions ?? 0, 'totalamount' => $amountStats->totalamount ?? 0 ];
方法2:子查询关联(单查询解决)
先对commissions和order_items按订单分组统计,再和orders关联,从根源避免笛卡尔积:
$getstats = Order::select( DB::raw('SUM(sc.total_commission) as totalcommissions'), DB::raw('SUM(oi.total_amount) as totalamount') ) // 子查询:按订单统计单订单佣金总额 ->leftJoin( DB::raw('(SELECT order_id, SUM(amount) as total_commission FROM commissions GROUP BY order_id) as sc'), 'sc.order_id', '=', 'orders.id' ) // 子查询:按订单统计单订单商品总额 ->leftJoin( DB::raw('(SELECT order_id, SUM(qty * each) as total_amount FROM order_items GROUP BY order_id) as oi'), 'oi.order_id', '=', 'orders.id' ) ->first();
方法3:集合汇总(Laravel集合处理)
先查询每个订单的佣金和金额,再通过集合方法汇总总数:
$getstats = Order::select( DB::raw('(SELECT SUM(amount) FROM commissions WHERE order_id = orders.id) as commission'), DB::raw('(SELECT SUM(qty * each) FROM order_items WHERE order_id = orders.id) as amount') )->get() ->reduce(function ($result, $order) { $result['totalcommissions'] += $order->commission ?? 0; $result['totalamount'] += $order->amount ?? 0; return $result; }, ['totalcommissions' => 0, 'totalamount' => 0]);
内容的提问来源于stack exchange,提问作者muya.dev
相关产品推荐
相关产品推荐

