Laravel中DB::raw与selectRaw的差异及使用疑问
为什么Laravel中withCount用DB::raw和selectRaw会返回不同结果?
这是个很典型的Laravel Eloquent用法误区,核心和withCount方法的设计初衷直接相关,咱们来理清楚:
1. withCount的默认定位
withCount从名字就能看出来,它的原生功能就是统计关联模型的行数。Laravel在处理这个方法时,会默认把关联子查询的聚合操作设置为count(*)——哪怕你在闭包里尝试用其他聚合函数,只要写法不对,就会被Laravel强制替换成计数逻辑。
2. select(DB::raw("SUM(points)"))生效的原因
当你用select(DB::raw(...))时,你传递的是一个原始SQL表达式,Laravel不会对这个表达式做任何解析或修改,会原封不动地把它插入到子查询中。所以你的SUM(points)能被MySQL正确执行,最终得到积分的求和结果。
3. selectRaw被替换成count(*)的原因
而selectRaw是Laravel提供的语法糖,它本质上还是会让Eloquent去解析你的查询逻辑。但因为你是在withCount的闭包里调用它,Laravel会优先遵循withCount的默认规则——把聚合操作强制改成count(*),直接忽略了你传入的SUM(points),所以最终得到的是关联数据的行数,而非积分总和。
4. 更合适的替代方案
如果你的Laravel版本在8.0及以上,更推荐用专门的withAggregate方法来做聚合统计(比如求和、平均值),写法更清晰,也不会踩这种坑:
User::withAggregate('points', 'points', 'sum')
这个方法会自动生成正确的SUM(points)子查询,返回你需要的积分总和。
如果是更低版本的Laravel,那继续用select(DB::raw("SUM(points)"))的写法就是最稳妥的选择。
内容的提问来源于stack exchange,提问作者Michał
相关产品推荐
相关产品推荐

