
本文介绍如何使用 laravel 的 query builder 对多表关联数据进行分组求和,解决因缺少 group by 导致重复行、无法汇总的问题,并给出正确实现与关键注意事项。
在实际开发中,常需基于主表(如 products)和关联表(如 ins 入库记录)统计每个商品的累计数量。你当前的查询虽然完成了表连接,但未进行分组(GROUP BY)和聚合(SUM()),导致每条入库记录单独返回一行,且 SUM() 在无分组时会对全表求和并复制到每一行——这正是你看到大量重复商品名和 null/零散数值的根本原因。
✅ 正确做法是:显式分组 + 聚合 + 选择非聚合字段需兼容 SQL 标准。以下是修正后的 Laravel 查询代码:
public function index()
{
$productsWithTotal = DB::table('products')
->join('ins', 'products.id', '=', 'ins.products_id')
->select('products.name', DB::raw('SUM(ins.amount) as total_amount'))
->groupBy('products.id', 'products.name') // ✅ 必须按主键和 SELECT 中的非聚合字段分组
->get();
return response()->json($productsWithTotal);
}? 关键说明:
- SUM(ins.amount) 计算每个商品所有入库记录的金额总和;
- GROUP BY products.id, products.name 是必需的:Laravel 使用 MySQL 严格模式时,若 SELECT 包含非聚合字段(如 name),必须将其纳入 GROUP BY,否则会报错或结果不可靠;
- 移除了原查询中多余的 ins.amount 字段——它属于明细数据,与汇总目标冲突;
- 使用 total_amount 作为别名更语义化,避免与原始字段混淆。
⚠️ 注意事项:
- 若某商品在 ins 表中无任何记录,该商品将不会出现在结果中(因使用 INNER JOIN)。如需包含零库存商品,应改用 LEFT JOIN 并配合 COALESCE(SUM(ins.amount), 0);
- 确保数据库字段类型支持数值运算(如 amount 应为 INT 或 DECIMAL,而非 VARCHAR);
- 生产环境建议添加索引:ins(products_id) 可显著提升 JOIN 性能。
最终输出示例:
[
{"name": "Aerobat", "total_amount": 124},
{"name": "god of war", "total_amount": 30},
{"name": "Rs537", "total_amount": 15}
]这一结构清晰、可直接用于前端展示或进一步业务处理。










