
本文介绍如何使用 laravel eloquent 和 query builder 一次性获取各状态的应用数量及全量总计,避免多次数据库查询,支持缺失状态补零(如 processed/failed 显示为 0),并适配 blade 模板渲染。
本文介绍如何使用 laravel eloquent 和 query builder 一次性获取各状态的应用数量及全量总计,避免多次数据库查询,支持缺失状态补零(如 processed/failed 显示为 0),并适配 blade 模板渲染。
在实际业务中,常需统计关联表(如 applications 与 status)中各状态的记录数,并同时展示“全部”汇总值。若采用多个独立 count() 查询(如 $total、$complete),不仅性能低、代码冗余,还无法自动包含无匹配记录的状态(如 processed 和 failed 当前为 0),导致前端需手动补全,易出错。
推荐方案:使用 LEFT JOIN + GROUP BY + UNION ALL 实现「全状态覆盖 + 总计行」
Laravel 中最简洁、健壮的实现方式是结合原生 SQL 逻辑与 Eloquent/Query Builder,确保:
- 所有 status 表记录均被包含(含 COUNT=0 的状态);
- 额外追加一行 All 总计;
- 结果结构统一,便于 Blade 直接遍历。
✅ 正确写法(推荐):
use Illuminate\Support\Facades\DB;
$statusStats = DB::table('status')
->select(
'status.id as 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')
->unionAll(
DB::table('applications')
->select(DB::raw('"All" as status_name'), DB::raw('COUNT(*) as count'))
->where('is_active', true)
)
->orderByRaw("CASE WHEN status_name = 'All' THEN 0 ELSE 1 END")
->orderBy('count', 'DESC')
->get();
? 关键说明:
- 使用 LEFT JOIN 确保 status 表所有行参与计算,即使 applications 中无匹配项,COUNT(applications.id) 自动为 0;
- UNION ALL 合并总计行,避免重复扫描;
- orderByRaw 将 "All" 行置顶,其余按状态名或数量排序;
- 字符串处理(UPPER/LOWER)实现首字母大写格式化,适配预期输出(Completed、Pending 等)。
? Blade 渲染示例(resources/views/stats.blade.php):
| Status | Total |
|---|---|
| {{ $row->status_name }} | {{ $row->count }} |
⚠️ 注意事项:
- 若 status.desc 含空格或特殊字符,建议在数据库中增加 display_name 字段替代动态格式化;
- UNION ALL 要求字段数与类型严格一致,此处通过别名对齐;
- 如需兼容 MySQL 5.7 或更低版本,请将 || 替换为 CONCAT() 函数;
- 生产环境建议为 applications.status_id 和 applications.is_active 建立复合索引以提升 JOIN 性能。
该方案仅执行 1 次数据库查询,返回结构化结果,兼顾可读性、扩展性与性能,是 Laravel 中处理「全维度分组统计 + 汇总行」的标准实践。











