预订日历到达和离开日期

Posted

技术标签:

【中文标题】预订日历到达和离开日期【英文标题】:Booking Calendar Arrive & Depart Dates 【发布时间】:2015-07-10 17:01:16 【问题描述】:

这似乎是一个典型的问题,但我找不到这个问题的答案。

我有一张预订桌:

book_id  |   arrive_date |   depart_date
1                 2015-07-20     2015-07-22 
2                 2015-07-22     2015-07-23  
3                 2015-07-19     2015-07-20  

你会看到我已经证明了出发日期可以是到达日期,反之亦然

在添加日期之前,我会检查日期范围是否与表格中的日期冲突,重要的是允许出发日期为到达日期,因为此人将要离开,当我检查时允许这样做表中的日期我使用以下 SQL 将日期添加到到达日期并从出发日期减去一天:

Select * From booking Where booking.unit_id = 58 
  And ( DATE_ADD(booking.from_date, INTERVAL 1 DAY) 
  BETWEEN '2015-07-23' AND '2015-07-24' 
   OR 
  DATE_SUB(booking.to_date, INTERVAL 1 DAY) 
   BETWEEN '2015-07-23' AND '2015-07-24' 
      OR '2015-07-23' 
   BETWEEN DATE_ADD(booking.from_date, INTERVAL 1 DAY) 
   AND DATE_SUB(booking.to_date, INTERVAL 1 DAY)) Limit 1  

当我添加第一个日期时,没问题...与第二个和第三个相同,这是因为我输入的第一个日期范围介于(20 日和 22 日)之间。然后我尝试添加'2015-07-23' AND '2015-07-24',使用上面的SQL进行检查,这显然是返回结果。我需要一种方法来允许这些日期被接受,因为 23 日是出发日期。

任何帮助将不胜感激

我还应该提到,我还有一个保存被阻止日期“booking_prev”的表,因此在输入之前也将使用类似的查询来检查预订表中的阻止日期。

【问题讨论】:

无需先检查。事实上,这会适得其反,因为有人可能会在你检查和接下来的任何事情之间插入一个值。 是的,虽然只有在预订表中没有日期的情况下才会显示并允许预订,但我仍然需要一种方法首先检查日期范围是否有效......请看看我有什么已添加。 您不需要先检查。 (除非使用事务)检查可以而且应该在插入期间进行。 如果你有一个很棒的建议......在另一部分我也只想在一个表格中插入日期,如果它们不在另一个表格中......不是确定如何在一次插入上完成。 【参考方案1】:

考虑以下...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(book_id  INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,arrive_date DATE NOT NULL
,depart_date DATE NOT NULL
);

INSERT INTO my_table VALUES
(1,'2015-07-20','2015-07-22'),
(2,'2015-07-22','2015-07-23'),
(3,'2015-07-19','2015-07-20');

SELECT * FROM my_table;
+---------+-------------+-------------+
| book_id | arrive_date | depart_date |
+---------+-------------+-------------+
|       1 | 2015-07-20  | 2015-07-22  |
|       2 | 2015-07-22  | 2015-07-23  |
|       3 | 2015-07-19  | 2015-07-20  |
+---------+-------------+-------------+

所以,SELECT 可能看起来像这样......

SELECT '2015-07-22','2015-07-24' 
  FROM (SELECT 1) x 
  LEFT 
  JOIN my_table y
    ON y.arrive_date < '2015-07-24' AND y.depart_date > '2015-07-22'
 WHERE y.book_id IS NULL 
 LIMIT 1;
Empty set (0.00 sec)

SELECT '2015-07-23','2015-07-24' 
  FROM (SELECT 1) x 
  LEFT 
  JOIN my_table y
    ON y.arrive_date < '2015-07-24' AND y.depart_date > '2015-07-23'
 WHERE y.book_id IS NULL 
 LIMIT 1;
+------------+------------+
| 2015-07-23 | 2015-07-24 |
+------------+------------+
| 2015-07-23 | 2015-07-24 |
+------------+------------+

...但您不需要先检查它们。我故意以这样一种方式编写 SELECT,以便检查可以作为 INSERT 的一部分进行......

INSERT INTO my_table (arrive_date,depart_date)
SELECT '2015-07-23','2015-07-24' 
  FROM (SELECT 1) x 
  LEFT 
  JOIN my_table y
    ON y.arrive_date < '2015-07-24' AND y.depart_date > '2015-07-23'
 WHERE y.book_id IS NULL 
 LIMIT 1;

SELECT * FROM my_table;
+---------+-------------+-------------+
| book_id | arrive_date | depart_date |
+---------+-------------+-------------+
|       1 | 2015-07-20  | 2015-07-22  |
|       2 | 2015-07-22  | 2015-07-23  |
|       3 | 2015-07-19  | 2015-07-20  |
|       4 | 2015-07-23  | 2015-07-24  |
+---------+-------------+-------------+

在实践中,根据您想要提供的用户体验,您可能希望先运行 SELECT,以便用户可以立即看到哪些日期不可用,然后在制作时运行 INSERT预订 - 确保在用户预订途中没有人抢到这些日期。

【讨论】:

非常感谢您花时间展示解决方案,插入就可以了。只是几个问题,这对我来说是新的,虽然它有效,但我无法理解 (SELECT)x 的作用,并且似乎无法找到解释。因为我只想在日期不在插入表和另一个表中时应用插入,所以我是否只需添加一个 OR FROM (SELECT 2) x LEFT JOIN my_other table z ON z.arrive_date '2015-07-23' WHERE z.book_id IS NULL :最后,我最初的想法是在插入之前检查 f,以便我可以告诉用户错误.. 这真的是一个 hack。我只需要一个虚拟表实例供 JOIN 使用。 x 是子查询的别名。【参考方案2】:

好的,虽然接受的答案做得很好,但我仍然需要检查日期条目是否有效,主要是因为我在将日期添加到阻止日期的表之前检查了主预订表中的日期。无论如何,下面的 SQL 似乎完成了我需要的所有检查:

Select * From booking Where booking.unit_id = 58 And ((booking.arrive_date < '2015-07-23' And booking.depart_date >= '2015-07-24') OR (booking.arrive_date <= '2015-07-23' And booking.depart_date > '2015-07-24') OR (booking.arrive_date >= '2015-07-23' And booking.depart_date <= '2015-07-24') OR ('2015-07-23' > booking.arrive_date And '2015-07-23' < booking.depart_date ) OR ('2015-07-24' > booking.arrive_date And '2015-07-24' < booking.depart_date )) Limit 1 

对于我给出的解决方案被标记下来有点失望,因为它确实检查了表中的值,这是我的要求之一,尽管对于实际插入来说并不是那么有效。

继续我已经扩展了接受的答案,添加了更多我正在使用的基于表格的字段来保存被阻止的预订日期:

INSERT INTO booking_prevent (unit_id,from_date,to_date,note) SELECT 58, '2015-07-28', '2015-07-29', 'My Note' FROM (SELECT 1) x LEFT JOIN booking_prevent y ON y .from_date '2015-07-28' And y.unit_id = 58 WHERE y.booking_prevent_id IS NULL LIMIT 1

这很好用,但我有点卡住了如何对条目进行更新但只进行更改...再次,如果它是有效的。这就是我所拥有的,这是在黑暗中刺伤:

UPDATE booking_prevent SET (unit_id,from_date,to_date,note) SELECT 58, '2015-07-20', '2015-07-26', 'Updated Note' FROM (SELECT 1) x LEFT JOIN booking_prevent y ON y .from_date '2015-07-20' And y.unit_id = 58 WHERE y.booking_prevent_id IS NULL WHERE booking_prevent_id = 466 LIMIT 1

任何指针将不胜感激。

【讨论】:

只要在您检查时没有人提交插入。 时间也是线性的——我的查询利用了这一事实

以上是关于预订日历到达和离开日期的主要内容,如果未能解决你的问题,请参考以下文章

用于检查房间可用性的 SQL 查询

jquery日历插件问题

绘制跨越午夜的到达和离开时间

酒店预订可能

在点击文本字段时显示日期选择器

sql每隔三天更新一次