You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化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();

关键修正点

  1. 修复DB::raw语法错误:原代码中DB::raw(AVG('pt.progress'))写法错误,AVG()需作为字符串传入DB::raw,正确格式为DB::raw('AVG(pt.progress)')
  2. 关联时过滤任务:通过leftJoin的闭包添加parent=0条件,避免关联无关数据
  3. 强制分组聚合:必须添加groupBy,否则AVG会计算全表符合条件的任务平均值,而非按单个项目独立聚合
  4. 对齐原逻辑:AVG(pt.progress)*100和原循环查询的(SUM(progress)*100)/count(progress)结果完全一致,因为AVG(progress) = SUM(progress)/COUNT(progress)

内容的提问来源于stack exchange,提问作者Aayush Dahal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:30:50