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

Laravel分组查询获取按供应商拆分的库存数据是否需要使用子查询

不需要完全重写现有查询,有两种实现方案,可根据业务场景选择,优先推荐ORM关联方案,可读性和可维护性更高。

方案一:Eloquent ORM 关联+集合后处理(推荐)

利用Laravel自带的关联预加载和集合操作实现,不需要调整复杂的SQL逻辑:

// 先确保StockPart模型已定义stockItems关联
class StockPart extends Model
{
    public function stockItems()
    {
        return $this->hasMany(StockItem::class);
    }
}

// 查询代码
$stockParts = StockPart::query()
    ->select(['id', 'title'])
    // 原有总库存统计
    ->withCount([
        'stockItems as available' => function ($query) use ($stockId) {
            $query->where('current_stock_id', $stockId);
        }
    ])
    // 原有总价值统计
    ->withSum([
        'stockItems.shipment as totalValue'
    ], 'item_cost')
    // 预加载关联数据用于供应商维度统计
    ->with(['stockItems' => function ($query) use ($stockId) {
        $query->where('current_stock_id', $stockId)
            ->select('id', 'stock_part_id', 'shipment_id')
            ->with('shipment:id,supplier_id,item_cost');
    }])
    ->orderBy('title')
    ->get()
    // 后处理生成按供应商分组的统计
    ->map(function (StockPart $stockPart) {
        $stockPart->available_by_seller = $stockPart->stockItems
            ->groupBy('shipment.supplier_id')
            ->map(function ($items, int $supplierId) {
                return [
                    'supplier_id' => $supplierId,
                    'available' => $items->count(),
                    'totalValue' => $items->sum('shipment.item_cost')
                ];
            })
            ->values();
        // 清理不需要的原始关联字段
        unset($stockPart->stockItems);
        return $stockPart;
    })
    ->toArray();

该方案适合大多数中小数据量场景,代码逻辑清晰,后续拓展其他统计维度成本低

方案二:原生SQL聚合(适合大数据量场景)

如果数据量较大,不想在PHP层面做后处理,可以修改现有查询,利用MySQL 5.7+支持的JSON聚合函数直接生成目标结构:

$q = DB::table('stock_parts')
    ->select('stock_parts.id', 'stock_parts.title')
    // 原有总统计
    ->selectRaw('COUNT(stock_items.id) AS available')
    ->selectRaw('SUM(shipments.item_cost) AS totalValue')
    // 按供应商聚合的临时字段
    ->selectRaw('JSON_OBJECT(
        "supplier_id", shipments.supplier_id,
        "available", COUNT(stock_items.id),
        "totalValue", SUM(shipments.item_cost)
    ) AS seller_stat')
    ->leftJoin('stock_items', function($join) use ($stockId) {
        $join->on('stock_items.stock_part_id', '=', 'stock_parts.id')
            ->where('stock_items.current_stock_id', $stockId);
    })
    ->leftJoin('shipments', 'shipments.id', '=', 'stock_items.shipment_id')
    // 分组维度新增供应商ID
    ->groupBy('stock_parts.id', 'stock_parts.title', 'shipments.supplier_id')
    ->orderBy('stock_parts.title', 'ASC')
    ->get()
    // 合并同一零件的多组供应商数据
    ->groupBy('id')
    ->map(function ($rows) {
        $baseData = $rows[0];
        // 合并总统计
        $baseData->available = $rows->sum('available');
        $baseData->totalValue = $rows->sum('totalValue');
        // 组装供应商统计数组
        $baseData->available_by_seller = $rows
            ->pluck('seller_stat')
            ->map(fn($json) => json_decode($json, true))
            ->filter(fn($stat) => !is_null($stat['supplier_id']))
            ->values();
        // 清理临时字段
        unset($baseData->seller_stat);
        return $baseData;
    })
    ->values()
    ->toArray();

该方案大部分逻辑在SQL层面执行,性能更好,但需要数据库支持JSON聚合函数,代码可读性稍低

内容的提问来源于stack exchange,提问作者anderlaini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 22:36:02