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

Laravel中如何使用WhereNotIn与with?修复物料日期可用查询报错

修复你的Eloquent物料可用查询问题

看起来你是想通过排除指定日期/时间段内已被占用的物料,来获取可用的物料。你的代码目前有几个明显的问题,我来一步步帮你修复:

1. 错误的whereNotIn用法

你现在直接把查询构建器实例传给whereNotIn,这不符合该方法的语法——whereNotIn需要第一个参数是字段名,第二个参数是要排除的值数组。这里更适合用whereDoesntHave来检查物料是否没有符合占用条件的关联订单,这比嵌套查询更直观、高效。

2. 时间段重叠的逻辑问题

判断两个时间段是否重叠的核心逻辑是:如果订单的时间段和查询的时间段有任何交集,那这个物料就是不可用的。我们需要排除这类物料,所以要检查物料的orders_material关联中不存在满足以下重叠条件的记录:

订单开始时间 <= 查询结束时间 且 订单结束时间 >= 查询开始时间

另外你提到了begin_hour和hour_final,需要把日期和小时组合成完整的时间范围来判断,避免只判断日期导致的误差。

修复后的完整代码

假设你的date_begin/date_final是日期字段,begin_hour/hour_final是小时字段(比如14:00:00格式),修复后的代码如下:

$availableMaterials = Material::whereDoesntHave('orders_material', function($query) use ($begin_date, $end_date, $begin_hour, $hour_final) {
    // 将日期和小时拼接为完整的datetime,再进行时间段重叠判断
    $query->whereRaw(
        "STR_TO_DATE(CONCAT(date_begin, ' ', begin_hour), '%Y-%m-%d %H:%i:%s') <= STR_TO_DATE(CONCAT(?, ' ', ?), '%Y-%m-%d %H:%i:%s')",
        [$end_date, $hour_final]
    )->whereRaw(
        "STR_TO_DATE(CONCAT(date_final, ' ', hour_final), '%Y-%m-%d %H:%i:%s') >= STR_TO_DATE(CONCAT(?, ' ', ?), '%Y-%m-%d %H:%i:%s')",
        [$begin_date, $begin_hour]
    );
})->get();

补充说明

  • 如果你的date_begin、date_final本身就是包含小时的datetime类型,那可以简化成直接比较:
    $query->where('date_begin', '<=', "$end_date $hour_final")
          ->where('date_final', '>=', "$begin_date $begin_hour");
    
  • whereDoesntHave会自动生成高效的子查询,只返回没有被占用的物料,比先加载所有关联再过滤的方式性能好很多。
  • 如果你需要同时加载未占用的关联记录(虽然通常不需要),可以在whereDoesntHave之外加上with('orders_material'),但注意不要在with的闭包里写过滤逻辑,否则会影响关联数据的完整性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:24:01