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

Laravel 8 Query Builder统计关联合同数量返回数据不全如何解决?

问题原因

  • 你当前使用Query Builder时默认调用的join是INNER JOIN逻辑,关联contracts表时会自动过滤掉没有关联合同的用户,这就是你总统计数只有80条、缺失23条无合同用户的核心原因。
  • 额外需要注意的是,你原代码未选择roles表的字段,无法拿到用户对应的角色信息;同时如果MySQL开启了ONLY_FULL_GROUP_BY模式(Laravel 8默认配置开启),你当前groupBy只写users.id会触发语法报错。

修复后的Query Builder写法

写法1:LEFT JOIN关联实现

DB::table('users')
    // 改用LEFT JOIN关联合同表,保留无合同的用户记录
    ->leftJoin('contracts', 'users.id', '=', 'contracts.user_id')
    // 如果存在用户role_id为空/无对应角色的情况,这里也改用leftJoin
    ->join('roles', 'roles.id', '=', 'users.role_id')
    ->select(
        'users.id', 
        'users.username', 
        'users.email', 
        'roles.name as role_name',
        DB::raw('COUNT(contracts.id) as numberOfContracts')
    )
    // 适配ONLY_FULL_GROUP_BY模式,所有非聚合字段都加入groupBy
    ->groupBy('users.id', 'users.username', 'users.email', 'roles.name')
    ->paginate(10);

写法2:子查询实现(兼容性、性能更优)

这种写法和你用EloquentwithCount的底层逻辑一致,不需要对主表多字段做groupBy,避免后续加字段还要修改groupBy的问题:

// 先构造合同计数子查询
$contractCountQuery = DB::table('contracts')
    ->select(DB::raw('COUNT(id) as numberOfContracts, user_id'))
    ->groupBy('user_id');

// 主查询关联子查询拿计数
DB::table('users')
    ->join('roles', 'users.role_id', '=', 'roles.id')
    ->leftJoinSub($contractCountQuery, 'contract_counts', 'users.id', '=', 'contract_counts.user_id')
    ->select(
        'users.id',
        'users.username',
        'users.email',
        'roles.name as role_name',
        // 无合同的用户计数默认填充0
        DB::raw('IFNULL(contract_counts.numberOfContracts, 0) as numberOfContracts')
    )
    ->paginate(10);

与Eloquent写法的差异说明

你用到的EloquentwithCount本质是用子查询做关联计数,不会过滤主表users的任何记录,所以能返回全部103条用户数据,上面的写法2就是Query Builder层面还原了Eloquent的实现逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 19:06:03