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

Laravel多Where子句查询不符合预期:获取过期列表数据异常问题

问题分析与解决方案

嘿,我发现你当前的查询逻辑有个关键问题——你用了三个独立的where()闭包,它们之间是AND关系,这意味着只有同时满足三个条件的记录才会被筛选出来,但这完全不符合你需要的「优先级判断过期日期」的规则。

你的需求逻辑回顾

我们需要按优先级取第一个非空的过期日期来判断是否过期:

  1. 优先用to_date_3(不为空时)
  2. to_date_3为空时用to_date_2(不为空时)
  3. 前两个都为空时用to_date_1

正确的查询写法(两种方案)

方案一:用查询构造器嵌套条件(逻辑清晰)

这种方式把每个优先级的判断封装成互斥的子条件,用orWhere()组合起来,完全贴合你的需求逻辑:

$query = Listing::query()
    ->where('vendor_id', $vendor->id)
    ->where('is_deleted', 0)
    ->where('is_published', 1)
    ->where('is_approved', 1)
    ->where(function ($q) {
        $currentDate = \Carbon\Carbon::now()->format('Y-m-d');
        
        // 条件1:to_date_3不为空且已过期
        $q->orWhere(function ($subQuery) use ($currentDate) {
            $subQuery->whereNotNull('to_date_3')
                     ->where('to_date_3', '<', $currentDate);
        })
        // 条件2:to_date_3为空,to_date_2不为空且已过期
        ->orWhere(function ($subQuery) use ($currentDate) {
            $subQuery->whereNull('to_date_3')
                     ->whereNotNull('to_date_2')
                     ->where('to_date_2', '<', $currentDate);
        })
        // 条件3:to_date_3和to_date_2都为空,to_date_1已过期
        ->orWhere(function ($subQuery) use ($currentDate) {
            $subQuery->whereNull('to_date_3')
                     ->whereNull('to_date_2')
                     ->where('to_date_1', '<', $currentDate);
        });
    })
    ->orderBy('created_at', 'desc');

$listings = $query->paginate(10);

方案二:用SQL的COALESCE函数(简洁高效)

COALESCE()函数会返回传入参数中第一个非NULL的值,刚好匹配我们的优先级规则,代码会更简洁:

$query = Listing::query()
    ->where('vendor_id', $vendor->id)
    ->where('is_deleted', 0)
    ->where('is_published', 1)
    ->where('is_approved', 1)
    // 直接取第一个非空的过期日期,判断是否小于当前日期
    ->whereRaw('COALESCE(to_date_3, to_date_2, to_date_1) < ?', [\Carbon\Carbon::now()->format('Y-m-d')])
    ->orderBy('created_at', 'desc');

$listings = $query->paginate(10);

关于你示例数据的验证

按你给出的示例数据和当前日期2021-08-21:

  • 记录1的to_date_3是2021-09-15(未过期),不会被选中
  • 记录2的to_date_2是2021-08-22(未过期),不会被选中
  • 记录3的to_date_1是2021-08-20(已过期),会被选中

如果你的预期结果是记录1和2,可能需要检查示例数据里的日期是否符合「已过期」的条件哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:27:33