如何优化Laravel查询,关联表获取指定条件的进度平均值
问题描述
现有Laravel查询中DB::raw(AVG('pt.progress'))报错,需优化关联查询逻辑,实现按项目聚合,获取同一project_id下parent=0的progress字段平均值,替代原循环查询的低效方案。
现有查询代码
$query = DB::table('projects as p') ->leftJoin('projects_tasks as pt','pt.project_id', 'p.id') ->select( 'p.id', 'p.project_name', DB::raw(AVG('pt.progress')) //此处需要获取平均值 ); $query->orderBy($order, $dir); if ($limit != -1) { $query->skip($start)->take($limit); } $records = $query->get();
表结构
projects: ======== id project_name ... projects_tasks: =============== id project_id parent // 取值为0或1 progress // 取值范围0.00至1.00
当前实现方式(需优化)
通过循环调用以下函数实现需求,但性能较低:
$data_row = DB::table('projects_tasks') ->select(DB::raw('(SUM(progress)*100)/count(progress) as project_progress')) ->where(['project_id' => $project_id, 'parent' => 0]) ->get();
优化后的关联查询方案
直接在关联查询中完成筛选、聚合逻辑,代码如下:
$query = DB::table('projects as p') ->leftJoin('projects_tasks as pt', function($join) { $join->on('pt.project_id', '=', 'p.id') ->where('pt.parent', '=', 0); // 仅关联parent=0的任务数据 }) ->select( 'p.id', 'p.project_name', DB::raw('AVG(pt.progress) * 100 as project_progress') // 等价于原逻辑的百分比平均值 ) ->groupBy('p.id', 'p.project_name') // 按项目分组,确保每个项目返回一条聚合结果 ->orderBy($order, $dir); if ($limit != -1) { $query->skip($start)->take($limit); } $records = $query->get();
关键修正点
- 修复
DB::raw语法错误:原代码中DB::raw(AVG('pt.progress'))写法错误,AVG()需作为字符串传入DB::raw,正确格式为DB::raw('AVG(pt.progress)') - 关联时过滤任务:通过
leftJoin的闭包添加parent=0条件,避免关联无关数据 - 强制分组聚合:必须添加
groupBy,否则AVG会计算全表符合条件的任务平均值,而非按单个项目独立聚合 - 对齐原逻辑:
AVG(pt.progress)*100和原循环查询的(SUM(progress)*100)/count(progress)结果完全一致,因为AVG(progress) = SUM(progress)/COUNT(progress)
内容的提问来源于stack exchange,提问作者Aayush Dahal
相关产品推荐
相关产品推荐

