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

如何复用Eloquent Builder两次获取结果?Laravel 9查询异常求助

问题原因

Eloquent Builder实例是**可变(Mutable)**的,和CarbonImmutable的不可变特性完全不同。你每次调用where、whereDate这类查询方法时,都会直接修改原Builder对象的查询条件,而非返回全新的实例。

所以第一次执行$expenses->whereDate('txn_date', '<', $start)->sum()时,txn_date < $start这个条件已经被追加到原$expenses实例中。后续再调用whereDate('txn_date', '>=', $start)时,最终的查询条件会变成:

WHERE contractor_id = ? AND txn_date < ? AND txn_date >= ? AND txn_date <= ?

时间条件互斥,自然返回空集合。而直接赋值$olderDebits = $expenses只是传递引用,并没有创建新的Builder实例,修改$olderDebits的条件本质还是在修改原$expenses。

解决方案

要复用基础查询逻辑,必须用clone关键字创建Builder实例的独立副本,这样每个副本的条件修改都不会影响原实例和其他副本:

// 构建基础查询
$expenses = PropertyExpense::with(['bill'])
            ->where('contractor_id', $supplier);

// 克隆副本用于计算期初余额
$oldDebitsQuery = clone $expenses;
$oldDebits = $oldDebitsQuery->whereDate('txn_date', '<', $start)
            ->sum('billed');

// 原实例用于查询时间段数据,不受之前的条件影响
$debits = $expenses
            ->whereDate('txn_date', '>=', $start)
            ->whereDate('txn_date', '<=', $end)
            ->get();

也可以简化写法,每次直接克隆原实例确保查询独立:

$baseQuery = PropertyExpense::with(['bill'])->where('contractor_id', $supplier);

$oldDebits = (clone $baseQuery)->whereDate('txn_date', '<', $start)->sum('billed');
$debits = (clone $baseQuery)->whereBetween('txn_date', [$start, $end])->get();

注:用whereBetween可以替代两个whereDate条件,让代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 20:50:29