在my question about searching for date ranges中,我尝试简化问题,无意中提出了一个不同且更简单的问题。
不是通过编辑使这个问题复杂化,而是要问我实际想要的问题。
我有两张表属性和预订。预订具有属性的外键以及开始和结束日期。
用户正在搜索空闲广告位并以天为单位提供所需的持续时间。他们还提供他们感兴趣的一系列开始日期。因此,搜索将按以下方式进行: “找到我所有的房产我想要一个3天的时间段,从5月开始。”
现在我可以这样做: 1.为每个潜在的开始日运行31个查询 2.查找5月份的所有预订,将它们压缩成一个31个布尔值的数组,代表天数,然后循环查找插槽。
我认为(2)在大多数情况下效率更高。有没有更好的算法?是否有纯SQL解决方案。
我将使用Django并且我的数据集很小所以我可能会对'哑'approuch感到满意,但我很想知道最好的算法是什么样的。
答案 0 :(得分:4)
你的申请可能有点过分 - 但是:
以“写入”过程变得更加复杂为代价来改进搜索的一种相对简单的方法是更改Booking表,使其成为“可用性”表。
添加一个布尔列以指示该插槽是空闲还是已预订(或者更好地保留在预订它的客户的ID中,如果插槽空闲则使用0)。
从一个免费插槽开始,2009年1月1日 - > 12月31日???
当您预订时,将免费插槽分为3个(两个插入和一个更新),预订的插槽和两个可用插槽。
继续这样做,随着时间框架变得更加分散,预订流程将包含以下其中一项:
管理并不是非常复杂,搜索过程变成了一个简单的查询:在所需的时间范围内找到任何可用的插槽(预订= false或customerid = 0,无论你采用哪种方式),其中enddate - startdate&gt ; =您想要的天数。
它使预订/可用性表的大小翻倍,并使预订变得不那么简单,但权衡的是搜索过程就像它一样容易。
答案 1 :(得分:4)
表定义会有所帮助,但这里有所帮助。这应该适用于MS SQL Server,但是一旦理解了它背后的想法,将它转换为MySQL应该是一项微不足道的任务。
Calendar表只是一个标准的实用程序表,其中包含数据库中的所有日期。如果您还没有,我建议您创建一个并填充它。
CREATE TABLE Calendar
(
date DATETIME NOT NULL,
is_holiday BIT NOT NULL,
-- any other columns that might be relevant for your business
CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (date)
)
然后,您需要使用可能对您的业务有意义的任何日期填充表格。即使您回溯100年并向前走100年,表中的行仍然少于75K,并且它集中在日期,因此它应该快速且易于使用。它使许多基于日期的查询更加简单。
SELECT
P.property_id,
C.date
FROM
Calendar C
JOIN Properties P ON 1=1
WHERE
C.date BETWEEN @search_start_date AND @search_end_date AND
NOT EXISTS
(
SELECT
*
FROM
Bookings B
WHERE
B.property_id = P.property_id AND
B.start_date <= DATEADD(dy, @slot_length, C.date) AND -- You would use MySQLs date function
B.end_date >= C.date
)
或者:
SELECT
P.property_id,
C.date
FROM
Calendar C
JOIN Properties P ON 1=1
LEFT OUTER JOIN Bookings B ON
B.property_id = P.property_id AND
B.start_date <= DATEADD(dy, @slot_length, C.date) AND -- You would use MySQLs date function
B.end_date >= C.date
WHERE
C.date BETWEEN @search_start_date AND @search_end_date AND
B.booking_id IS NULL