php - 为什么涉及不同年份时按日期范围查询不起作用?
问题描述
我在 Laravel 中有一个关于日期范围的查询,这让我想起了。最初查询工作没有错误,但我检测到如果日期范围在不同年份(12-2020 到 01-2021)之间,它不会返回任何记录。我有点厌倦了检查代码,我没有看到问题。
我在这里放置了将数据保存在数组中的查询,以及稍后我在返回值之前应用日期过滤器进行的检查。
public function getData($filters) {
$tasks = $this->getModel()
->whereIn('tasks.department_id', $filters['departmentIds'])
->join('departments', 'departments.id', '=', 'tasks.department_id')
->join('deliverables as dev', 'dev.id', '=', 'tasks.deliverable_id')
->leftJoin('deliverables as sub', 'sub.id', '=', 'tasks.subdeliverable_id')
->leftJoin('workers as st_workers', 'st_workers.id', '=', 'tasks.start_worker_id')
->leftJoin('workers as end_workers', 'end_workers.id', '=', 'tasks.end_worker_id')
->leftJoin('type_task_statuses', 'type_task_statuses.id', '=', 'tasks.status_id')
->leftJoin('incidences', 'incidences.task_id', '=', 'tasks.id')
->select('tasks.id', 'departments.name as department', 'tasks.start_worker_id', 'tasks.end_worker_id', 'st_workers.short_name as start_worker',
'end_workers.short_name as end_worker', 'tasks.plane', 'tasks.st', 'dev.name as deliverable', 'sub.name as subdeliverable',
'tasks.quantity', 'tasks.other_deliverable', 'tasks.start_prevision_date', 'tasks.end_prevision_date', 'tasks.start_date',
'tasks.end_date', 'tasks.prevision_hour', 'tasks.incurred_hour', 'type_task_statuses.display_name as status', 'type_task_statuses.color', 'tasks.advance', 'tasks.agreed',
'tasks.disagreed_date', 'tasks.supervised', DB::raw('COUNT(incidences.id) as count_incidences'))
->groupBy('tasks.id');
if (array_key_exists('fromDate', $filters) && $filters['fromDate']) {
$tasks->whereRaw('(DATE_FORMAT(tasks.end_date, "%m-%Y") >= "'.$filters['fromDate'].'" OR tasks.end_date is NULL)');
}
if (array_key_exists('toDate', $filters) && $filters['toDate']) {
$tasks->whereRaw('(DATE_FORMAT(tasks.end_date, "%m-%Y") <= "'.$filters['toDate'].'" OR tasks.end_date is NULL)');
}
return $tasks;
}
解决方案
我建议将您的输入格式化为应用程序中的日期范围,而不是在数据库端应用格式化,请参阅我对anit-patterns的另一个答案
假设您有以下输入以匹配数据库中的日期
$filters['fromDate'] ='12-2020';
$filters['toDate'] = '01-2021';
这实际上相当于以下日期范围
从 2020-12-01 00:00:00 到 2021-01-31 23:59:59
因此,让我们尝试将过滤器输入转换为此范围格式
/** 2020-12-01 00:00:00 */
$fromDate = \Carbon\Carbon::createFromFormat('d-m-Y', '01-'.$filters['fromDate'])->startOfMonth()->format('Y-m-d H:i:s');
/** 2021-01-31 23:59:59 */
$toDate = \Carbon\Carbon::createFromFormat('d-m-Y', '01-'.$filters['toDate'])->endOfMonth()->format('Y-m-d H:i:s');
现在,您可以轻松地在查询中应用这些范围,并且在数据库方面,您不需要任何格式
if (array_key_exists('fromDate', $filters) && $filters['fromDate']) {
$fromDate = \Carbon\Carbon::createFromFormat('d-m-Y', '01-' . $filters['fromDate'])->startOfMonth()->format('Y-m-d H:i:s');
$tasks->where(function ($query) use ($fromDate) {
$query->whereNull('tasks.end_date')
->orWhere('tasks.end_date', '>=', $fromDate);
});
}
if (array_key_exists('toDate', $filters) && $filters['toDate']) {
$toDate = \Carbon\Carbon::createFromFormat('d-m-Y', '01-' . $filters['toDate'])->endOfMonth()->format('Y-m-d H:i:s');
$tasks->where(function ($query) use ($toDate) {
$query->whereNull('tasks.end_date')
->orWhere('tasks.end_date', '<=', $toDate);
});
}
推荐阅读
- javascript - Vite.js 不在多页应用程序中发出 HTML 文件
- variables - 内核全局变量存储在哪里?
- javascript - 使用 Kendo JavaScript 在 PDF 文件上打印图像
- javascript - 从函数数组 HTML/Javascript 填充日期
- javascript - 返回的 json 响应是 undefended django
- java - 如何在 React Native 中的自定义 TextInput 组件中保持焦点?(安卓)
- javascript - 无法访问方法 reactjs 中的道具
- python - 无法使用请求模块从网页中抓取表格内容
- kubernetes - Loki 设置为 Prometheus 数据源以便对日志计数发出警报,配置错误,出现 404 错误
- c - C循环If语句?