Laravel下按多时段筛选过期房源的SQL返回结果错误如何修复
问题原因
你的现有逻辑存在漏洞:仅在高优先级的to_date_*字段(to_date_3/to_date_2)非空且已过期时才中断判断,若高优先级字段非空但未过期,代码会继续向下判断低优先级的to_date字段,只要低优先级字段过期就会把房源加入结果,完全违背了「只判断最新的非空to_date_*字段」的规则。
以你给出的示例为例,假设当前时间为2021-08-22:
- id=2的最新非空to_date是
to_date_2=2021-08-25(未过期),本不应返回,但现有代码判断to_date_2未过期后,继续判断to_date_1=2021-08-10(已过期),就错误把id=2加入了结果 - id=1的最新非空to_date是
to_date_3=2021-09-15(未过期),本不应返回,但现有代码判断to_date_3未过期后,继续判断低优先级字段,最后因to_date_1过期错误加入结果
修复方案
方案1:修改集合过滤逻辑(快速适配现有代码)
调整判断规则:只要高优先级to_date_*字段非空,无论是否过期都只判断该字段,判断后直接终止逻辑,不再查看更低优先级的字段:
$now = \Carbon\Carbon::now()->toDateString(); $listings = $all_listings->filter(function ($lis) use ($now) { // 非空就只判断最高优先级的to_date_3 if (!is_null($lis->to_date_3)) { return $lis->to_date_3 < $now; } // to_date_3为空才判断to_date_2 if (!is_null($lis->to_date_2)) { return $lis->to_date_2 < $now; } // 前两个都为空才判断to_date_1 return $lis->to_date_1 < $now; });
方案2:SQL层直接过滤(更推荐)
你原来的写法是先分页再过滤,会导致每页实际返回数量不足(比如分页配置10条,过滤后只剩3条),直接在查询阶段过滤可以避免这个问题,性能也更高:
$now = \Carbon\Carbon::now()->toDateString(); $all_listings = Listing::query() ->where('vendor_id', $vendor->id) ->where('is_deleted', 0) ->where('is_published', 1) ->where('is_approved', 1) ->where('lease_term', '!=', 'long_term') // 核心过期判断逻辑 ->whereRaw(' CASE WHEN to_date_3 IS NOT NULL THEN to_date_3 < ? WHEN to_date_2 IS NOT NULL THEN to_date_2 < ? ELSE to_date_1 < ? END = 1 ', [$now, $now, $now]) ->orderBy('created_at', 'desc') ->paginate(10);
修改后查询出来的结果直接符合要求,不需要再二次遍历过滤。
内容的提问来源于stack exchange,提问作者Osama Shaki
相关产品推荐
相关产品推荐

