Laravel多日期范围查询异常求助:可用性日历关联查询问题
问题根源分析
你当前的查询逻辑要求单条availabilityCalendar记录完全包含在用户指定的日期范围内,但你的实际需求是用户指定的日期范围与可用记录区间存在重叠,或是被可用记录完全覆盖,二者逻辑完全不匹配。另外你的表中存在无效记录(id=2的start_date大于end_date),这也会干扰查询结果。
解决方案
情况1:只要用户日期范围与任意可用记录有重叠就返回
这是多日期搜索的常见需求,判断两个日期区间是否存在交集的标准逻辑是:现有区间的start_date ≤ 用户的end_date,且现有区间的end_date ≥ 用户的start_date。
修改后的Laravel查询代码:
$listings->whereHas( 'availabilityCalendar', function ($query) use ($start_date, $end_date) { $query->where('start_date', '<=', $end_date) ->where('end_date', '>=', $start_date); } );
情况2:用户整个日期范围必须被可用记录完全覆盖(无空档)
如果需要确保用户选择的每一天都有对应的可用记录,需要更复杂的查询,以下提供两种实现方式:
方式1:通过计算覆盖天数验证
// 计算用户指定日期范围的总天数 $userRangeDays = \Carbon\Carbon::parse($start_date)->diffInDays(\Carbon\Carbon::parse($end_date)) + 1; $listings->whereHas( 'availabilityCalendar', function ($query) use ($start_date, $end_date, $userRangeDays) { $query->selectRaw('listing_id, SUM(DATEDIFF(LEAST(end_date, ?), GREATEST(start_date, ?)) + 1) as covered_days', [$end_date, $start_date]) ->where('start_date', '<=', $end_date) ->where('end_date', '>=', $start_date) ->groupBy('listing_id') ->havingRaw('covered_days = ?', [$userRangeDays]); } );
方式2:排除存在空档的房源
$listings->whereDoesntHave( 'availabilityCalendar', function ($query) use ($start_date, $end_date) { $query->whereRaw("NOT EXISTS ( SELECT 1 FROM availability_calendar ac WHERE ac.listing_id = listings.id AND ac.start_date <= DATE_ADD(?, INTERVAL 1 DAY) AND ac.end_date >= ? )", [$end_date, $start_date]); } );
额外修正:处理无效日期记录
你的availabilityCalendar表中id=2的记录start_date=2023-02-26大于end_date=2023-02-10,属于无效日期区间,必须先修正这条记录(例如改为start_date=2023-02-01, end_date=2023-02-10)。同时建议在表中添加约束防止此类错误:
ALTER TABLE availability_calendar ADD CONSTRAINT chk_valid_date_range CHECK (start_date <= end_date);
内容的提问来源于stack exchange,提问作者bhdrnzl
相关产品推荐
相关产品推荐

