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

Laravel非Eloquent实现多关联计数查询 解决统计值乘积错误问题

问题原因

你当前的写法问题核心是多表JOIN产生了笛卡尔积:当同时JOINaddresses、cars两张关联表时,每个用户的每条地址记录会和该用户所有车辆记录匹配生成组合行,最终单用户的总数据行数等于「地址数量 × 车辆数量」,直接count两个关联表的id自然会得到完全相同、且等于乘积的错误结果。

解决方案

Eloquent的withCount底层实际是用子查询单独统计每个关联的数量,不会联表产生笛卡尔积,你可以用两种方式复现相同逻辑:

方式1:直接用select子查询(写法最简洁,和withCount行为完全一致)

$users = \DB::table('users')
    ->select([
        'id',
        'name',
        \DB::raw('(SELECT COUNT(*) FROM addresses WHERE addresses.user_id = users.id) as addresses_count'),
        \DB::raw('(SELECT COUNT(*) FROM cars WHERE cars.user_id = users.id) as cars_count')
    ])
    ->get();

方式2:先单独统计关联表数据再JOIN(适合大表统计场景)

先分别对两张关联表做分组统计,再和用户表JOIN,避免笛卡尔积:

// 先统计每个用户的地址数量
$addressStats = \DB::table('addresses')
    ->selectRaw('user_id, COUNT(id) as addresses_count')
    ->groupBy('user_id');

// 先统计每个用户的车辆数量
$carStats = \DB::table('cars')
    ->selectRaw('user_id, COUNT(id) as cars_count')
    ->groupBy('user_id');

// 关联统计结果和用户表
$users = \DB::table('users')
    ->leftJoinSub($addressStats, 'address_stats', 'users.id', '=', 'address_stats.user_id')
    ->leftJoinSub($carStats, 'car_stats', 'users.id', '=', 'car_stats.user_id')
    ->select(
        'users.id',
        'users.name',
        \DB::raw('IFNULL(addresses_count, 0) as addresses_count'),
        \DB::raw('IFNULL(cars_count, 0) as cars_count')
    )
    ->get();

两种写法都兼容没有关联数据的用户,统计结果和原EloquentwithCount完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:45:04