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

Laravel同一字段设置两个where条件查询结果异常咨询

查询创建时间距当前30~365天数据的问题排查

问题背景

需要查询所有创建时间距当前日期为30~365天前的数据,编写的两段代码均无法返回预期结果。

测试基础信息

  • 测试基准日期:2022-06-10
  • 测试表结构与样本数据:
id     created_at
1      2022-05-09   
2      2021-06-08
  • 预期返回规则:
    • id=2的记录距基准日超过365天,不应返回
    • id=1的记录距基准日超过30天但不足365天,为目标返回结果

异常代码与现象

测试代码1

$today = Carbon::now();
$doubtfulLoan = Loan::select('*')
->where(function($query) use ($today) {
    return $query
    ->where('created_at', '<', $today->subDays(30)->endOfDay())
    ->where('created_at', '>=', $today->subDays(365)->endOfDay());
 })
->get();
  • 运行结果:返回空数组
  • 补充测试现象:
    • 注释第二个where子句时,返回id=1、id=2两条记录
    • 注释第一个where子句时,仅返回id=1的记录
    • 两个条件同时生效时返回空数组

测试代码2

$today = Carbon::now();
$doubtfulLoan = Loan::select('*')
   ->where([
       ['created_at', '<', $today->subDays(30)->endOfDay()], 
       ['created_at', '>=', $today->subDays(365)->endOfDay()]
   ])->get();
  • 运行结果:返回全部两条记录,不符合预期

问题根因

Carbon默认是可变对象,所有日期加减、时间修改类方法都会原地修改当前实例并返回自身。两段代码出错的核心原因都是复用同一个$today实例多次调用修改方法,导致查询条件的时间边界被意外篡改:

  1. 代码1中,第一次subDays(30)先将$today修改为30天前的时间,后续subDays(365)是在已经偏移30天的基础上再减365天,实际总共偏移了395天;且传入查询构造器的是同一个对象引用,两个条件最终拿到的时间值逻辑互斥,因此返回空数组。
  2. 代码2中,数组参数在传入查询方法前会完成全部求值,两次subDays同样修改了同一个$today实例,导致时间边界偏移,最终把超过365天的记录也纳入了返回结果。

修复方案

核心原则是保证两个查询条件的时间边界独立计算,不要在同一个Carbon实例上连续做修改操作。

方案1:提前定义独立的时间边界变量

调用修改方法前用copy()复制新实例,避免互相干扰:

$now = Carbon::now();
// 早于该时间 = 距当前超过30天
$threshold30 = $now->copy()->subDays(30)->endOfDay();
// 晚于等于该时间 = 距当前不足365天
$threshold365 = $now->copy()->subDays(365)->endOfDay();

$doubtfulLoan = Loan::query()
    ->where('created_at', '<', $threshold30)
    ->where('created_at', '>=', $threshold365)
    ->get();

方案2:链式调用时实时复制实例

如果不想提前定义变量,每次调用修改方法前都链式调用copy()生成新实例:

$today = Carbon::now();
$doubtfulLoan = Loan::query()
    ->where('created_at', '<', $today->copy()->subDays(30)->endOfDay())
    ->where('created_at', '>=', $today->copy()->subDays(365)->endOfDay())
    ->get();

方案3:使用不可变Carbon类

Carbon 2.0+提供了不可变类CarbonImmutable,所有修改类方法都会自动返回新实例,不会出现原地修改的问题,数组写法也可以直接正常使用:

$today = CarbonImmutable::now();
$doubtfulLoan = Loan::query()
    ->where([
        ['created_at', '<', $today->subDays(30)->endOfDay()],
        ['created_at', '>=', $today->subDays(365)->endOfDay()]
    ])->get();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 12:48:08