
在 Laravel 9 中,若需对子表(如 coletes)按父表(invoices)ID 分组求和,必须使用 groupBy() 明确指定分组字段;否则 SUM() 将全局聚合,导致所有记录合并为单个总和。
在 laravel 9 中,若需对子表(如 coletes)按父表(invoices)id 分组求和,必须使用 `groupby()` 明确指定分组字段;否则 `sum()` 将全局聚合,导致所有记录合并为单个总和。
要在发票详情页中正确展示每张发票下所有对应 coletes 的明细及小计,并在底部显示该发票的 totaleuro 总和(例如 invoice ID=1 → 700,ID=2 → 1000),关键在于按 invoice_id 分组聚合,而非全局求和。
原始查询缺失 GROUP BY,因此数据库将全部 coletes.totaleuro 直接相加,返回单一结果 1700。修复方式是在查询链中添加 ->groupBy('coletes.invoice_id'),确保聚合作用于每个发票维度:
$invoiceTotals = DB::table('coletes')
->join('invoices', 'coletes.invoice_id', '=', 'invoices.id')
->select(
'coletes.invoice_id',
DB::raw('SUM(coletes.totaleuro) as total_euro')
)
->groupBy('coletes.invoice_id')
->orderBy('coletes.invoice_id')
->get();
该查询将返回集合:
[
{"invoice_id": 1, "total_euro": 700},
{"invoice_id": 2, "total_euro": 1000}
]
在 Blade 模板中,可结合 Eloquent 关系实现更清晰的结构化渲染。推荐定义模型关系后使用预加载:
// 在 Invoice 模型中
public function coletes()
{
return $this->hasMany(Colet::class, 'invoice_id');
}
控制器中:
$invoices = Invoice::with('coletes')->get();
Blade 示例(支持明细 + 小计):
@foreach ($invoices as $invoice)
<h3>Invoice #{{ $invoice->id }}</h3>
| Colete ID | Total Euro |
|---|---|
| {{ $colet->id }} | {{ $colet->totaleuro }} |
| Total: | {{ $invoice->coletes->sum('totaleuro') }} |
⚠️ 注意事项:
- 使用
DB::table()原生查询时,groupBy字段必须与SELECT中非聚合列严格一致(如coletes.invoice_id),否则在严格 SQL 模式下会报错; - 若需关联其他字段(如发票编号、日期),应在
SELECT中一并列出,并加入GROUP BY; - 对于大数据量,建议在
coletes.invoice_id上建立索引以提升JOIN和GROUP BY性能; - 避免在循环中调用
sum()方法(如$invoice->coletes->sum(...))处理大量数据——应优先通过数据库聚合(即groupBy + SUM)减少内存开销。
综上,分组聚合是实现父子层级汇总的核心,合理选择原生查询或 Eloquent 关系,兼顾性能与可维护性。











