【发布时间】:2011-06-29 05:14:47
【问题描述】:
背景/应用
我有一个 MySQL 数据库,其中包含一个可出租物业表和一个这些物业的预订表。还有一个搜索功能可以在两个提供的日期之间查找可用的属性。搜索时,用户可以输入开始日期、他们希望停留的天数以及最多 +/- 7 天的日期灵活性。一个预订可以在另一个预订结束的同一天开始(第 1 方在早上离开,第 2 方在晚上到达)。
我很难有效地实现灵活性功能。
架构
CREATE TABLE IF NOT EXISTS `property` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `property_booking` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`property_id` bigint(20) DEFAULT NULL,
`name` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`date_start` date DEFAULT NULL,
`date_end` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
样本数据
INSERT INTO `property` (`name`)
VALUES ('Property 1'), ('Property 2'), ('Property 3');
INSERT INTO `property_booking` (`property_id`,`name`,`date_start`,`date_end`)
VALUES (1, 'Steve', '2011-03-01', '2011-03-08'),
(2, 'Bob', '2011-03-13', '2011-03-20'),
(3, 'Jim', '2011-03-16', '2011-03-23');
示例场景
用户选择他们想在 2011 年 3 月 10 日开始逗留,他们想逗留 7 天,并且他们有 +/- 2 天的灵活性。我已经编译了一个图像,可以将下面的数据和参数可视化。 (红色:预订 1,绿色:预订 2,条纹:预订 3,蓝色:日期范围(2011 年 3 月 10 日,+ 7 天和 +/- 2 天的灵活性))
预期结果
物业 1 (在整个日期范围内均可预订)
物业 3 (可从 2011 年 3 月 8 日或 2011 年 3 月 9 日开始预订)
当前方法
我当前的查询检查整个可搜索日期范围内所有 7 天的日期范围是否重叠,如下所示:
SELECT p.`id`, p.`name`
FROM `property` p
WHERE (NOT (EXISTS (SELECT p2.`name` FROM `property_booking` p2 WHERE (p2.`property_id` = p.`id` AND '2011-03-10' < DATE_SUB(p2.`date_end`, INTERVAL 1 DAY) AND '2011-03-17' > DATE_ADD(p2.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p3.`name` FROM `property_booking` p3 WHERE (p3.`property_id` = p.`id` AND '2011-03-11' < DATE_SUB(p3.`date_end`, INTERVAL 1 DAY) AND '2011-03-18' > DATE_ADD(p3.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p4.`name` FROM `property_booking` p4 WHERE (p4.`property_id` = p.`id` AND '2011-03-09' < DATE_SUB(p4.`date_end`, INTERVAL 1 DAY) AND '2011-03-16' > DATE_ADD(p4.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p5.`name` FROM `property_booking` p5 WHERE (p5.`property_id` = p.`id` AND '2011-03-12' < DATE_SUB(p5.`date_end`, INTERVAL 1 DAY) AND '2011-03-19' > DATE_ADD(p5.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p6.`name` FROM `property_booking` p6 WHERE (p6.`property_id` = p.`id` AND '2011-03-08' < DATE_SUB(p6.`date_end`, INTERVAL 1 DAY) AND '2011-03-15' > DATE_ADD(p6.`date_start`, INTERVAL 1 DAY)))));
在示例数据集上,它相当快,但在更大的数据集上,它会变得相当缓慢,当您构建完整的 +/- 7 天灵活性时更是如此。
有人对如何更好地编写此查询有任何建议吗?
【问题讨论】:
-
如果您可以随意更改数据库的模型,这个其他 SO question 对这个问题有一个很好的答案stackoverflow.com/questions/781221/…
-
+1 表示我见过的最好的问题。
标签: mysql date date-range