Laravel关联查询不使用JOIN实现关联字段分组求和
Eloquent 无JOIN实现关联字段分组求和方案
全程不需要写JOIN连表逻辑,有两种可落地的实现方式,根据你的数据量场景选择即可:
方案1:分两次单表查询做聚合(推荐,适合大数据量场景)
性能最优,不会把全量明细数据加载到内存,全程都是单表查询,没有任何JOIN操作:
- 第一步先根据主表筛选条件,拿到符合要求的消费记录主键ID集合
// 只查询主表符合条件的ID,不加载冗余字段 $validConsumptionIds = Consumption::whereIn('ambulance_id', $subset) ->whereBetween('document_date', [$old_from_date, $old_until_date]) ->pluck('id');
- 第二步直接查询
consumption_items表,按item_stock_id分组对quantity求和,需要关联的后续表直接正常用with预加载即可
$groupedResult = ConsumptionItem::with('item_stock.invoice_item.measure_unit') ->whereIn('consumption_id', $validConsumptionIds) ->selectRaw('item_stock_id, SUM(quantity) AS total_quantity') ->groupBy('item_stock_id') ->get();
返回的结果里,每一项对应一个item_stock_id的总消耗量,同时已经预加载了你需要的所有关联数据,全程无JOIN。
方案2:基于已查询的结果用集合做分组聚合(适合小数据量场景)
如果你已经按原代码把所有数据都查出来了,且后续逻辑还要用到全量的$consumptions数据,可以直接用Laravel集合的方法做处理,不需要额外发SQL查询:
$groupedResult = $consumptions // 把所有主模型下关联的consumption_item提取成扁平集合 ->pluck('consumption_item') ->flatten() // 按item_stock_id分组 ->groupBy('item_stock_id') // 对每组计算总量,同时保留关联数据 ->map(function ($groupItems, $stockId) { return (object)[ 'item_stock_id' => $stockId, 'total_quantity' => $groupItems->sum('quantity'), 'item_stock' => $groupItems->first()->item_stock ]; });
选型说明
- 单表数据量超过1000条优先选方案1,内存占用低、查询速度快,完全符合无JOIN的要求;
- 小数据量场景选方案2,代码更简洁,不需要额外查询。
- 如果你的模型关联外键不是默认的
consumption_id,把方案1里的对应字段改成你实际的外键名即可,MySQL开启严格模式下方案1的查询也能正常运行,不会报语法错误。
内容的提问来源于stack exchange,提问作者Cristian25
相关产品推荐
相关产品推荐

