You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel关联查询不使用JOIN实现关联字段分组求和

Eloquent 无JOIN实现关联字段分组求和方案

全程不需要写JOIN连表逻辑,有两种可落地的实现方式,根据你的数据量场景选择即可:


方案1:分两次单表查询做聚合(推荐,适合大数据量场景)

性能最优,不会把全量明细数据加载到内存,全程都是单表查询,没有任何JOIN操作:

  1. 第一步先根据主表筛选条件,拿到符合要求的消费记录主键ID集合
// 只查询主表符合条件的ID,不加载冗余字段
$validConsumptionIds = Consumption::whereIn('ambulance_id', $subset)
    ->whereBetween('document_date', [$old_from_date, $old_until_date])
    ->pluck('id');
  1. 第二步直接查询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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:27:13