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
相关产品推荐
相关产品推荐

