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

Laravel 9 withSum查询报错:where子句中credit_balance列不存在

问题解决:Laravel 9中withSum后无法用where过滤聚合字段的问题

错误原因

你用withSum生成的credit_balance是Eloquent在主查询执行完成后,对每个模型的关联数据做求和计算得到的字段,这个字段并不存在于原始SQL查询中,所以直接用where('credit_balance', '<', 100)会触发数据库报错,因为数据库找不到这个列。

正确实现方式

方式一:使用having过滤聚合结果

having是SQL中专门用于过滤聚合函数结果的语句,Laravel支持直接用having来过滤withSum生成的别名:

/**
 * 获取所有可自动充值的密钥
 */
public function getEnabledTopUpKeys()
{
    return PersonalAccessToken::whereNotNull('region_code')
                              ->where('auto_topup_enabled', true)
                              ->whereNotNull('auto_topup_slug')
                              ->withSum('credit_transactions AS credit_balance', 'delta')
                              ->having('credit_balance', '<', 100)
                              ->get();
}

如果上述写法在某些Laravel版本中不生效,可以改用havingRaw确保语法正确:

->havingRaw('credit_balance < ?', [100])

方式二:用子查询提前计算聚合值并过滤

如果需要在SQL层面直接完成过滤(避免事后集合过滤的性能损耗),可以用子查询在select中计算余额,再通过having过滤:

/**
 * 获取所有可自动充值的密钥
 */
public function getEnabledTopUpKeys()
{
    return PersonalAccessToken::whereNotNull('region_code')
                              ->where('auto_topup_enabled', true)
                              ->whereNotNull('auto_topup_slug')
                              ->selectRaw('personal_access_tokens.*, (SELECT SUM(delta) FROM credit_transactions WHERE credit_transactions.personal_access_token_id = personal_access_tokens.id) AS credit_balance')
                              ->having('credit_balance', '<', 100)
                              ->get();
}

这种方式的优势是聚合计算和过滤都在一次SQL查询中完成,性能更优,同时也能直接返回credit_balance字段。

方式三:结合whereRaw和子查询过滤

如果你只需要过滤结果,同时还要保留withSum生成的字段,可以在whereRaw中嵌入子查询:

/**
 * 获取所有可自动充值的密钥
 */
public function getEnabledTopUpKeys()
{
    return PersonalAccessToken::whereNotNull('region_code')
                              ->where('auto_topup_enabled', true)
                              ->whereNotNull('auto_topup_slug')
                              ->whereRaw('(SELECT SUM(delta) FROM credit_transactions WHERE credit_transactions.personal_access_token_id = personal_access_tokens.id) < ?', [100])
                              ->withSum('credit_transactions AS credit_balance', 'delta')
                              ->get();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:35:16