如何在 Laravel 中按产品名称汇总入库数量(GROUP BY 实战)

如何在 Laravel 中按产品名称汇总入库数量(GROUP BY 实战)

本文教你使用 laravel 的 query builder 正确实现多表关联 + 分组聚合,解决“查询每个产品名称及其入库总数量”这一常见需求,避免重复数据与 null 值干扰。

在实际开发中,我们常需基于一对多关系(如 products 表与 ins 入库记录表)统计聚合值。你当前的代码执行了 JOIN,但未进行分组(GROUP BY),也未显式调用聚合函数(如 SUM())配合分组——这导致数据库返回每条匹配记录的原始行(例如 Aerobat 出现 7 次),而非每个产品的唯一汇总结果。

✅ 正确做法需同时满足三点:

  1. 使用 GROUP BY 按产品维度分组(此处为 Products.name);
  2. 对数值字段使用聚合函数(如 SUM(ins.amount)),并处理可能的 NULL;
  3. 在 SELECT 中明确声明分组字段与聚合字段,避免 SQL 错误(尤其在严格模式下)。

以下是优化后的完整示例(含健壮性增强):

public function index()
{
    $productsWithTotal = DB::table('products')
        ->leftJoin('ins', 'products.id', '=', 'ins.products_id') // 改用 LEFT JOIN 确保无入库记录的产品也不丢失
        ->select(
            'products.name',
            DB::raw('COALESCE(SUM(ins.amount), 0) as total_amount') // SUM 处理 NULL → 0
        )
        ->groupBy('products.id', 'products.name') // 推荐按主键 + 业务字段双重分组,避免歧义
        ->get();

    return response()->json($productsWithTotal);
}

? 关键说明与注意事项:

LAIKA

LAIKA

LAIKA 是一个创意伙伴,您可以训练它像您(或您想要的任何人)一样写作。

下载

  • 必须加 GROUP BY:仅写 SUM() 而不 GROUP BY 会导致 MySQL 报错(sql_mode=only_full_group_by 启用时)。Laravel 不自动添加,需手动指定。
  • 推荐 LEFT JOIN:若某产品暂无入库记录(ins 表无对应行),INNER JOIN 会将其过滤掉;LEFT JOIN 则保留该产品,并通过 COALESCE(SUM(…), 0) 将其 total_amount 设为 0。
  • 分组字段要完整:GROUP BY products.id, products.name 比仅 GROUP BY products.name 更安全(防止同名不同产品被错误合并)。
  • 避免 ->get() 后再 PHP 聚合:数据库层面聚合(SUM + GROUP BY)性能远高于 PHP 循环累加,尤其在大数据量时。

最终输出将符合预期格式:

[
  {"name": "Aerobat", "total_amount": 70},
  {"name": "god of war", "total_amount": 30},
  {"name": "Rs537", "total_amount": 0}
]

掌握此模式后,你可轻松扩展至其他聚合场景(如 COUNT(*) 统计入库次数、AVG() 计算平均单次入库量等)。

https://www.php.cn/faq/1989498.html

发表回复

Your email address will not be published. Required fields are marked *