啊,应该给我加标签的,一年多后我才看到这个!你现在可能已经想出了如何工作,但为了完整起见,我还是会尝试一下,因为我认为这里的大多数答案都不是你想要的。
所以你遇到的问题是,在另一个问题中,每个房间都有一个唯一的 ID,而且人们有兴趣预订的是唯一的房间。在这里,您将可预订项目的概念扩展到特定类别的项目池(在本例中为汽车模型)。
可能有一种方法可以在没有子查询的情况下做到这一点,但到目前为止,最简单的方法是简单地从我的另一个答案中获取原始想法,并通过将其包装在另一个将其分组为模型的查询中来扩展它(并且当你很快就会看到,我们可以免费获得一堆其他有用的东西)。
因此,首先让我们首先获取具有冲突预订计数的汽车列表(根据我的另一个答案的更新):
(我将使用您对这些示例的查询作为起点,但请注意,您确实应该使用准备好的语句,或者至少为您传递的两个参数使用数据库驱动程序提供的转义函数)
SELECT car_id, model_id, SUM(IF(rental_id IS NULL, 0, rental_start_date <= '$ddate' AND rental_end_date >= '$adate')) AS ConflictingReservations
FROM test_tbl_cars
LEFT JOIN test_reservations USING (car_id)
GROUP BY car_id
这将为每个 car_id 返回一行,为您提供型号,以及与您指定的日期范围(0 或更多)冲突的预订数量。
现在在这个阶段,如果我们询问单个汽车(而不仅仅是可用的汽车型号),我们可以使用“HAVING ConflictingReservations = 0 ORDER BY model_id”或其他内容来限制和排序结果。
但是,如果我们想要获得 ~models~ 的可用性列表,我们需要对这些结果进行进一步分组以获得最终答案:
SELECT model_id, COUNT(*) AS TotalCars, SUM(ConflictingReservations = 0) AS FreeCars, CAST(IFNULL(GROUP_CONCAT(IF(ConflictingReservations = 0, car_id, NULL) ORDER BY car_id ASC), '') AS CHAR) AS FreeCarsList
FROM (
SELECT car_id, model_id, SUM(IF(rental_id IS NULL, 0, rental_start_date <= '$ddate' AND rental_end_date >= '$adate')) AS ConflictingReservations
FROM test_tbl_cars
LEFT JOIN test_reservations USING (car_id)
GROUP BY car_id
) AS CarReservations
GROUP BY model_id
您会注意到我们所做的只是按 model_id 对原始查询进行分组,然后使用聚合函数来获取 model_id,我们拥有该模型的汽车总数,我们拥有的该模型的免费汽车数量我们通过计算一辆车的冲突保留为零的所有时间来实现,最后是一段可爱的 SQL,它返回一个逗号分隔的空闲汽车的 car_id 列表(以防万一也需要!)
简单说一下性能:所有的左连接、分组和子查询确实会使这个查询变得非常慢。好消息是外部 group by 应该只需要处理与你有汽车一样多的行,所以在你最终得到大量汽车之前它不应该很慢。然而,内部查询连接两个表(可以通过索引快速完成),然后按整个集合分组,对每一行执行功能。这可能会变得相当缓慢,特别是随着预订和汽车数量的增加。为了缓解这种情况,您可以在内部查询中使用 where 子句,并将其与适当的索引结合起来,以减少您正在检查的项目数量。您还可以使用其他技巧将开始日期和结束日期的比较移动到连接条件中,但这是另一天的主题:)
最后,和往常一样,如果有不正确的边缘情况、错误、错误的语法等等——请告诉我,我会进行编辑以纠正!