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

Laravel模型关联场景下,如何查询指定时段全可用用户?

查询指定时段内完全可用的用户

问题说明

现有User与Availability模型,关联关系为User hasMany Availabilities,对应user_availability表数据如下:

id  | user_id |      date 
123 |  12345  |   2024-02-01   
124 |  12345  |   2024-02-02
125 |  12345  |   2024-02-03
126 |  45678  |   2024-02-01 
127 |  45678  |   2024-02-03  

需要筛选出指定时段内每一天都有可用记录的用户。比如查询2024-02-01至2024-02-03时,仅返回user_id=12345,user_id=45678因缺少2024-02-02的记录需排除。

原控制器查询代码:

$query->whereHas('availabilities', function ($query) use ($periodStartDate, $periodEndDate) {
    $query->fullyAvailable($periodStartDate, $periodEndDate);
});

原Availability模型的scopeFullyAvailable函数逻辑错误,会返回所有在时段内有任意可用记录的用户,不符合需求。

修正方案

方案一:修改Scope函数

核心逻辑是统计用户在指定时段内的可用日期数量,必须等于时段的总天数。修改后的Scope函数如下:

public function scopeFullyAvailable($query, $startDate, $endDate)
{
    $start = Carbon::parse($startDate);
    $end = Carbon::parse($endDate);
    $totalDays = $start->diffInDays($end) + 1; // 计算时段总天数,加1是因为包含首尾两天

    return $query->whereDate('date', '>=', $start)
                ->whereDate('date', '<=', $end)
                // 在这里添加你的额外筛选条件,比如->where('status', 'available')
                ->groupBy('user_id')
                ->havingRaw('COUNT(DISTINCT date) = ?', [$totalDays]);
}

方案二:简化控制器查询(更高效)

直接利用whereHas的第三个参数指定关联记录的数量要求,无需复杂Scope:

$start = Carbon::parse($periodStartDate);
$end = Carbon::parse($periodEndDate);
$totalDays = $start->diffInDays($end) + 1;

$query->whereHas('availabilities', function ($query) use ($start, $end) {
    $query->whereDate('date', '>=', $start)
          ->whereDate('date', '<=', $end);
          // 这里添加你的额外筛选条件
}, '=', $totalDays);

原代码错误原因

原Scope中的循环whereDate会生成多个AND条件,但外层的orWhere导致逻辑变成“满足额外筛选 或者 存在任意一个指定日期的记录”,这和“每一天都要有记录”的需求完全相反,自然会返回所有在时段内有记录的用户。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 00:57:27