我在如何在我正在处理的网站上实现搜索功能时遇到了麻烦。
搜索表单有两个字段,即用户想要租用车辆的起始日期和结束日期。
在数据库中,我有两个表,一个用于车辆,另一个表用于可用日期。
Table: cars
- car_id (int)
- name (varchar)
- description (varchar)
Table: cars_availability
- car_id (int)
- date (datetime)
- status (int) // 1: available 2: booked
cars_availability 中的每一行代表关联汽车可供出租或预订的日期。
问题:
如果用户搜索可从 5.feb.2013 到 8.feb.2013 的汽车,我想查询选择所有的汽车可供用户选择的所有日期使用。
我目前尚未完成的解决方案:
我知道我可以使用类似的东西遍历所有日子
$begin = new \DateTime( date('Y-m-d', strtotime($data['rent_start'])));
$end = new \DateTime( date('Y-m-d', strtotime($data['rent_end'])));
$end = $end->modify( '+1 day' );
$interval = \DateInterval::createFromDateString('1 day');
$period = new \DatePeriod($begin, $interval, $end);
$available_cars = array();
foreach ( $period as $dayTime ){
// query the cars and joining the cars_availabilty table
$item = DB::select('cars.*')
->from('cars')
->join('cars_availability')->on('cars_availability.item_id', '=', 'cars.item_id')
->where('items_availability.date', '=', $dayTime->format("Y-m-d H:i:s"))
->and_where('items_availability.status', '=', 1)
->execute()->as_array();
if(count($item) > 0){
if(isset($available_cars[$item[0]['item_id']])){
$available_cars[$item[0]['item_id']][] = $item[0];
}else{
$available_cars[$item[0]['item_id']] = array();
$available_cars[$item[0]['item_id']][] = $item[0];
}
}
}
在此之后,我会有一系列可能有所有日子可用的车辆,但我需要做一些额外的数学计算才能找到它。
我想知道是否有更优雅的解决方案来解决这个问题,可能会使用更好的查询。
如果你能给我任何反馈,我将非常感激。
由于
答案 0 :(得分:2)
这实际上是一个相当理智的查询设置。就个人而言,我建议遵循@inhan的建议,特别是如果事实证明汽车可以预订更短的时间(几小时?)。但是,由于边缘情况,查询会变得有点复杂(如果你在这里看一下,你应该找到相关的例子)。
不幸的是,我无法谈论它如何适合您的框架,但SQL可能如下所示:
SELECT Cars.car_id, Cars.name, Cars.description
FROM Cars
JOIN (SELECT car_id
FROM Cars_Availability
WHERE `date` >= '2013-02-05'
AND `date` < '2013-02-09'
AND status = 1
GROUP BY car_id
HAVING COUNT(*) = DATEDIFF('2013-02-09', '2013-02-05')) Available
ON Available.car_id = Cars.car_id
(有一个SQL Fiddle Example)
此查询假设每天只有一个条目,或者这个条目中断。基本上,它抓取每个“可用”行大于/等于开始日期,小于“结束”日期(日期/时间/时间戳是......复杂; this article处理SQL Server特定的问题,但基本概念适用),并确保它们之间的天数。大多数情况下,您正在寻找HAVING
条款
鉴于Cars_Availability
上的正确索引,它甚至可能不会出现在桌面上,这也是一个很好的表现。