我正在尝试根据机器人表的 start_date 和 end_date 列的值应用一组不同的日期过滤器
状况
问题
查询的
WHEN
部分的应用方式存在问题,尽管 start_date 和 end_date 列都是 NULL
,但它仍然进入第二个 WHEN
查询,导致在应该有数据时没有返回数据返回 500 条数据
代码
$robot = App\Robot::with([
'computer_vision_detections' => function ($query) {
$query->leftJoin('cv_detection_object_values', function ($join) {
$join->on('computer_vision_detections.detection_object_id', '=', 'cv_detection_object_values.id')
->whereColumn('computer_vision_detections.detection_type_id', '=', 'cv_detection_object_values.detection_type_id');
})
->leftJoin('robots', 'computer_vision_detections.serial_number', '=', 'robots.serial_number')
->select(
'computer_vision_detections.*',
'cv_detection_object_values.detection_type_id AS cv_detection_object_values_detection_type_id',
'cv_detection_object_values.id AS cv_detection_object_values_id_detection_object_id',
'cv_detection_object_values.description AS cv_detection_object_values_description'
)
->where(function ($query) {
$query->when(
DB::raw('robots.start_date IS NULL AND robots.end_date IS NULL'),
function ($q) {
$q->whereNotNull('computer_vision_detections.id'); // Take all data if both start and end are null
}
)
->when(
DB::raw('robots.start_date IS NULL AND robots.end_date IS NOT NULL'),
function ($q) {
$q->whereRaw('DATE(computer_vision_detections.created_at) <= DATE(robots.end_date)'); // All data before or equals to end date
}
);
});
},
'computer_vision_detections.detection_type' // This assumes the relationship is defined properly
])
->find(9434);
调试
当
WHEN
查询只是简化为这一个条件时,它能够返回 500 个数据条目,这向我表明查询的这一部分没有问题,并且问题是由于第二个 WHEN
尽管 end_time 为
NULL
,但查询仍在执行,因此导致返回的条目为 0
->where(function ($query) {
$query->when(
DB::raw('robots.start_date IS NULL AND robots.end_date IS NULL'),
function ($q) {
$q->whereNotNull('computer_vision_detections.id'); // Take all data if both start and end are null
}
);
});
有时您可能希望将某些查询子句应用于基于另一个条件的查询。这个例子:
$role = $request->input('role');
$users = DB::table('users')
->when($role, function (Builder $query, string $role) {
$query->where('role_id', $role);
})
->get();
这里有第一个参数,称为 $role
,如果它为 true,则
where
将添加到查询中。但是,您对
when
的期望是根据查询的部分结果有条件地添加查询部分。然而,事实并非如此。首先,您编写(或在本例中生成)查询,然后执行它,只有这样您才会知道结果是什么。在构造查询时,您还没有查询的结果,因此
robots.start_date IS NULL AND robots.end_date IS NOT NULL
不会被有意义地评估,而您得到的是
DB::raw('some text here')
是否为 truey。
DB::raw
返回一个
\Illuminate\Database\Query\Expression
,如果不是
null
,则始终为 true,并且它不会与您想要的检查有意义地等效。您可以采用以下方法来代替当前的方法:
->whereRaw('
CASE
WHEN robots.start_date IS NULL AND robots.end_date IS NOT NULL THEN computer_vision_detections.id IS NOT NULL
WHEN robots.start_date IS NULL AND robots.end_date IS NOT NULL THEN DATE(computer_vision_detections.created_at) <= DATE(robots.end_date)
ELSE TRUE
END
')
这将您的第一个案例封装在第一个WHEN
中,因此如果满足,则检查另一个字段是否为
null
,第二个案例与您的日期比较,如果两者都不是,则返回到
TRUE
是正确的。 [1]:https://laravel.com/docs/11.x/queries#conditional-clauses