
本文介绍如何使用 laravel 的 query builder 对多对一关联的库存表进行分组聚合,正确计算每个产品的入库总量,并避免因缺少 group by 导致的重复与空值问题。
在实际开发中,我们常需统计某类产品在多个入库记录中的总数量(如 Aerobat-34 表示 Aerobat 产品累计入库 34 件)。但直接 JOIN 后调用 sum() 而不配合 GROUP BY,会导致 SQL 语义错误或结果异常——正如提问者所见:原始查询返回了大量重复产品名 + 单条 amount 记录,甚至含 null 值,根本无法体现“每个产品总和”。
根本原因在于:SUM() 是聚合函数,必须配合 GROUP BY 指定分组维度(此处为产品名称),否则数据库会尝试对全表聚合,而 Laravel 默认不会自动添加 GROUP BY。
✅ 正确写法如下(Laravel 9+):
public function index()
{
$productsWithTotal = DB::table('products')
->join('ins', 'products.id', '=', 'ins.products_id')
->select('products.name', DB::raw('COALESCE(SUM(ins.amount), 0) as total'))
->groupBy('products.id', 'products.name') // 关键:按主键和名称分组,确保一致性
->get();
return response()->json($productsWithTotal);
}? 关键说明:
- ->groupBy('products.id', 'products.name'):必须包含 products.id(主键),避免仅按 name 分组时因重名导致误合并;同时加上 name 便于 SELECT 中引用;
- COALESCE(SUM(...), 0):将 NULL 总和(如某产品无任何入库记录)转为 0,提升数据健壮性;
- 若希望包含无入库记录的产品(即 LEFT JOIN 场景),应改用:
->leftJoin('ins', 'products.id', '=', 'ins.products_id')并保持 GROUP BY 不变,此时 COALESCE 更为必要。
⚠️ 注意:原答案中仅加 DB::raw('sum(ins.amount) as total') 但未添加 groupBy(),在严格模式 MySQL 或 PostgreSQL 下会直接报错(如 SQLSTATE[42000]: Syntax error or access violation),因此该写法不可直接使用。
最终输出格式示例:
[
{"name": "Aerobat", "total": 34},
{"name": "God of war", "total": 30},
{"name": "Rs537", "total": 15}
]总结:聚合查询 ≠ 简单加 SUM(),务必同步声明 GROUP BY;结合 COALESCE 和 LEFT JOIN 可覆盖更完整的业务场景。










