Laravel多Pivot表关联求和查询结果错误,请求排查
问题排查与解决方案
问题根源
你当前的查询同时对product_warehouse和product_purchase做左连接,会产生笛卡尔积。比如某个商品在product_warehouse有1条入库记录(数量3),在product_purchase有2条出库记录,join后会生成2条重复的入库记录,sum时就会把3算成6,导致结果偏大。
修正方案
以下是两种可行的解决思路:
思路1:子查询分别统计入库/出库量(适用于入库减出库的剩余库存)
先单独统计每个商品的总入库量和总出库量,再关联计算剩余库存,彻底避免笛卡尔积:
Product::select('products.id', 'products.code') ->selectRaw('COALESCE(warehouse.total_in, 0) - COALESCE(purchase.total_out, 0) as remaining_quantity') ->leftJoinSub( ProductWarehouse::select('product_id', DB::raw('sum(quantity) as total_in')) ->groupBy('product_id'), 'warehouse', 'warehouse.product_id', '=', 'products.id' ) ->leftJoinSub( ProductPurchase::select('product_id', DB::raw('sum(quantity) as total_out')) ->groupBy('product_id'), 'purchase', 'purchase.product_id', '=', 'products.id' ) ->groupBy('products.id') ->fromCompany() ->get();
说明:
leftJoinSub用来生成入库、出库的统计子表,每个商品仅对应一条统计记录COALESCE处理无入库/出库记录的场景,返回0而非null,避免计算结果为null
思路2:先聚合库存表再关联(仅需统计入库总量时)
如果你的"剩余库存"仅指入库总量,可先对库存表聚合求和,再关联主表:
Product::select('products.id', 'products.code') ->selectRaw('COALESCE(warehouse.total_quantity, 0) as remaining_quantity') ->leftJoin( ProductWarehouse::select('product_id', DB::raw('sum(quantity) as total_quantity')) ->groupBy('product_id'), 'warehouse', 'warehouse.product_id', '=', 'products.id' ) ->groupBy('products.id') ->fromCompany() ->get();
说明:先完成库存表的聚合,再和主表关联,每个商品仅对应一条库存统计数据,不会被采购表的多条记录重复放大。
额外提示
- 执行
查询语句->toSql()获取原始SQL,在数据库客户端运行,可直观查看join后的结果集,确认是否存在重复记录 - 检查
fromCompany()作用域是否正确过滤了当前公司的数据,避免跨公司数据干扰
内容的提问来源于stack exchange,提问作者Sharif
相关产品推荐
相关产品推荐

