Laravel 查询实现:筛选交易金额大于关联分配记录金额总和的交易
解决方案:数据库层面筛选未分配余额的交易
这问题我之前也遇到过,直接在数据库层面过滤确实比加载所有数据再处理高效太多,给你几个可行的方案,都是通过Laravel查询构造器生成原生SQL完成过滤:
方法1:使用Laravel的withSum便捷方法(推荐)
如果你的Laravel版本在7.0及以上,withSum是最简洁的方式,它会自动帮你计算关联模型的字段总和,然后我们用havingRaw来做聚合后的条件判断:
Transaction::where('contact_id', $id) // 计算当前交易对应的所有分配记录的amount总和,生成字段transaction_allocations_sum_amount ->withSum('allocations', 'amount') // 比较交易的amount是否大于分配总和,COALESCE处理无分配记录的情况(总和为0) ->havingRaw('transactions.amount > COALESCE(transaction_allocations_sum_amount, 0)') // 可选:如果交易的amount可能为NULL,加上这个条件排除无效数据 ->whereNotNull('amount') ->get();
方法2:子查询作为WHERE条件
如果你用的Laravel版本较低,或者更倾向于手动控制子查询逻辑,可以用这种方式:
use Illuminate\Support\Facades\DB; Transaction::where('contact_id', $id) ->whereNotNull('amount') ->where(function ($subQuery) { // 子查询:计算当前交易的分配记录总和,无记录则返回0 $subQuery->selectRaw('COALESCE(SUM(amount), 0)') ->from('transaction_allocations') ->whereColumn('transaction_id', 'transactions.id'); }, '<', DB::raw('transactions.amount')) ->get();
这里的子查询会为每一条交易计算对应的分配总和,然后直接和交易的amount做比较,完全在数据库层面完成过滤。
方法3:左连接+分组聚合
这种方式通过左连接关联两张表,然后分组计算总和,再用havingRaw过滤:
Transaction::select('transactions.*') ->leftJoin('transaction_allocations', 'transactions.id', '=', 'transaction_allocations.transaction_id') ->where('transactions.contact_id', $id) ->whereNotNull('transactions.amount') ->groupBy('transactions.id') // 比较交易amount和分配总和,无分配记录时总和为0 ->havingRaw('transactions.amount > COALESCE(SUM(transaction_allocations.amount), 0)') ->get();
注意事项
- 一定要用
COALESCE处理无分配记录的情况,否则没有分配记录的交易总和会是NULL,NULL和任何值比较都会返回false,导致这类交易被漏掉。 - 如果你的交易表中
amount字段允许为NULL,记得加上whereNotNull('amount'),因为NULL > 任何值的结果都是false,这类交易不符合需求。
内容的提问来源于stack exchange,提问作者Lucid Polygon
相关产品推荐
相关产品推荐

