
本文介绍如何使用 laravel eloquent 和 query builder 高效实现「关联表分组计数 + 全量总计」,避免多次查询,一次性获取各状态数量及“all”汇总行。
本文介绍如何使用 laravel eloquent 和 query builder 高效实现「关联表分组计数 + 全量总计」,避免多次查询,一次性获取各状态数量及“all”汇总行。
在实际业务中,常需统计某实体(如 applications)按关联状态(如 status 表)分类的数量,并同时展示总记录数(即“All”行)。若对每个状态单独调用 count(),不仅代码冗余、性能低下,还无法保证数据一致性(尤其在高并发场景下)。理想方案应一次查询完成所有统计,并兼容缺失状态(如 processed 和 failed 当前无对应应用,仍需显示 0)。
✅ 推荐方案:LEFT JOIN + GROUP BY + UNION ALL(兼顾完整性与准确性)
仅用 JOIN(内连接)会遗漏 status 表中无匹配应用的记录(如 id=3,4),导致 processed 和 failed 状态不出现。因此,必须使用 LEFT JOIN 从 status 主表出发:
use Illuminate\Support\Facades\DB;
$stats = DB::table('status')
->select(
'status.id',
DB::raw('UPPER(LEFT(status.desc, 1)) || LOWER(SUBSTRING(status.desc, 2)) as status_name'), // 首字母大写(如 'completed' → 'Completed')
DB::raw('COUNT(applications.id) as count')
)
->leftJoin('applications', function ($join) {
$join->on('status.id', '=', 'applications.status_id')
->where('applications.is_active', true);
})
->groupBy('status.id', 'status.desc')
->orderBy('status.id')
->get();
// 构造“All”行
$total = $stats->sum('count');
$allRow = (object) [
'id' => null,
'status_name' => 'All',
'count' => $total
];
// 合并结果(All 在首行)
$result = collect([$allRow])->merge($stats)->values();
? 关键点说明:
- LEFT JOIN 确保所有 status 记录都参与统计,即使无匹配应用,COUNT(applications.id) 自动为 0;
- WHERE 条件置于 JOIN ON 子句内(而非 WHERE 后),避免将 LEFT JOIN 退化为 INNER JOIN;
- 使用 UPPER/LOWER 或 ucwords()(PHP端处理)实现标题格式化,更灵活可控。
⚠️ 注意事项
-
Eloquent 模型关联优化:若已定义 Status 模型及其 applications() 关系,可改用 Eloquent 方式(但需注意 withCount() 不支持 LEFT JOIN 的零值保留,仍推荐原生查询):
// 不推荐用于零值场景 —— withCount 默认 INNER JOIN Status::withCount(['applications as count' => fn($q) => $q->where('is_active', true)])->get(); -
数据库兼容性:DB::raw() 中的字符串函数(如 UPPER, SUBSTRING)在 MySQL/PostgreSQL 语法略有差异,生产环境建议统一用 PHP 处理格式化:
$stats->map(function ($item) { $item->status_name = ucfirst($item->desc); return $item; }); -
性能提示:确保 applications.status_id 和 applications.is_active 字段有联合索引:
CREATE INDEX idx_app_status_active ON applications(status_id, is_active);
✅ 最终 Blade 渲染示例
| Status | Total |
|---|---|
| {{ $row->status_name }} | {{ $row->count }} |
该方案以单次高效查询解决多维度统计需求,兼具可读性、健壮性与扩展性,是 Laravel 中处理“主表全量 + 关联计数”场景的标准实践。











