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

如何优化校验日期范围是否已被占用的Eloquent查询

Eloquent查询优化方案
  • 第一阶段:抽离公共条件简化冗余代码
    你原有代码中三个OR子句都包含状态非取消的判断,可以直接把该条件提到最外层全局生效,同时可以用whereBetween简化日期区间判断,优化后代码如下:
$bookings = Booking::where('status', '!=', Booking::STATUS_CANCELED)
    ->where(function ($q) use ($start, $end) {
        $q->whereBetween('started_at', [$start, $end])
          ->orWhereBetween('ends_at', [$start, $end])
          ->orWhere(fn ($q) => $q->where('started_at', '<', $start)->where('ends_at', '>', $end));
    })->get();
  • 第二阶段:简化时间重叠判断逻辑
    判断两个时间段是否存在重叠有通用的简化公式,不需要拆分三种场景:只要已有预约的开始时间 < 传入结束时间,且已有预约的结束时间 > 传入开始时间,即判定为重叠。如果你的业务允许边界时间重合(如前一预约结束时间等于后一预约开始时间不算冲突),可以把运算符调整为<=/>=,优化后代码如下:
$bookings = Booking::where('status', '!=', Booking::STATUS_CANCELED)
    ->where('started_at', '<', $end)
    ->where('ends_at', '>', $start)
    ->get();

该逻辑和你原有实现完全等价,代码量大幅缩减。

  • 进阶优化:复用查询逻辑
    如果这类判断在项目中多处使用,可以在Booking模型中定义本地作用域,后续调用更简洁易维护:
    首先在模型文件中注册作用域:
// app/Models/Booking.php
class Booking extends Model
{
    const STATUS_CANCELED = 'canceled'; // 你的原有状态定义

    public function scopeNotCanceled($query)
    {
        return $query->where('status', '!=', self::STATUS_CANCELED);
    }

    public function scopeOverlapping($query, $start, $end)
    {
        return $query->where('started_at', '<', $end)
            ->where('ends_at', '>', $start);
    }
}

业务代码直接调用即可:

$bookings = Booking::notCanceled()->overlapping($start, $end)->get();

小提示:原代码中使用的!==运算符在Eloquent查询构造器中推荐替换为标准的!=,避免部分数据库驱动解析异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 23:06:03