Laravel如何仅对status为Approved的模型执行withCount关联统计
Laravel 实现基于模型自身属性的条件withCount关联统计
核心原理
when()方法只能基于查询构建时传入的外部变量判断是否追加SQL片段,无法实现逐行根据主表字段值动态决定统计逻辑。withCount()本质是生成相关子查询做聚合,子查询执行时可以访问主表当前行的字段值,我们只需要在统计的子查询内部追加主表字段的判断条件即可。
方案1:直接在withCount闭包中追加条件(最简洁)
直接在两个统计规则的闭包中,追加对projects表status字段的判断,非Approved状态的项目统计结果会自动返回0:
Project::select('id', 'number', 'name', 'status') ->withCount([ 'rmgs as project_rmg_submitted' => static function ($query): void { $query->where('projects.status', 'Approved') ->where('submitted', true); }, 'rmgs as project_rmg_unsubmitted' => static function ($query): void { $query->where('projects.status', 'Approved') ->where('submitted', false); } ]) ->get()
如果你希望非Approved状态的项目统计值返回null而非0,可以通过原生SQL改写聚合逻辑:
use Illuminate\Support\Facades\DB; Project::select('id', 'number', 'name', 'status') ->withCount([ 'rmgs as project_rmg_submitted' => static function ($query): void { $query->select(DB::raw('IF(projects.status = "Approved", COUNT(*), NULL)')) ->where('submitted', true); }, 'rmgs as project_rmg_unsubmitted' => static function ($query): void { $query->select(DB::raw('IF(projects.status = "Approved", COUNT(*), NULL)')) ->where('submitted', false); } ]) ->get()
方案2:模型层定义条件关联(适合多处调用场景)
如果这个统计逻辑在多个业务场景下复用,可以在Project模型中预先定义带约束的关联方法,避免重复编写闭包条件,后续查询直接调用关联即可:
// app/Models/Project.php // 已提交RMG统计关联:仅项目为Approved状态时生效 public function submittedRmgsForApproved() { return $this->hasMany(Rmg::class) ->where('submitted', true) ->whereRaw('projects.status = "Approved"'); } // 未提交RMG统计关联:仅项目为Approved状态时生效 public function unsubmittedRmgsForApproved() { return $this->hasMany(Rmg::class) ->where('submitted', false) ->whereRaw('projects.status = "Approved"'); }
查询代码可以简化为:
Project::select('id', 'number', 'name', 'status') ->withCount([ 'submittedRmgsForApproved as project_rmg_submitted', 'unsubmittedRmgsForApproved as project_rmg_unsubmitted' ]) ->get()
注意:不要在
get()查询完成后,通过遍历集合的方式逐项目做统计,这种写法会产生N+1查询问题,数据量较大时性能损耗非常明显,所有聚合统计优先在SQL层完成。
内容的提问来源于stack exchange,提问作者NicuVlad
相关产品推荐
相关产品推荐

