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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:15:30