我正在使用PHP和MySQL构建一个简单的可用性日历。
我有一张表存储物业的可用日期(目前所有这些都是7天的块)
available_dates:
start_date DATE
end_date DATE
available_id INT PRIMARY KEY
property_id INT
booked TINYINT(1)
一张预订日期表,引用我available_id
表的available_dates
:
bookings
booking_id INT
available_id INT
***user details***
我计划为每个属性添加一行添加到available_dates以标记可以预订的日期,然后在有人预订阻止时在该表上设置预订标志。
我想要做的是显示一个日期列表(在x
天的块中,在这种情况下为7),没有可用性集 - 所以日期不会出现在该表中 - 因为接下来的24个月左右。
我无法解决这个问题,而且我 知道 有一种更简单的方法可以实现这一点,这是我在循环每个属性时的第一个想法,然后每个块7天等等。
任何人都可以启发我吗?
更新
感谢@ZaneBien精彩而全面的回答,我已经成功地使用他的yeardate
表格和表格获得了我需要的结果。程序。
我所做的是当需要显示没有可用性集的日期的页面时,如果没有CURYEAR()+2
的话,PHP会调用该程序添加更多的日期。
然后得到我的结果,稍微修改了Zane的查询版本:
SELECT
a.yeardate AS blockstart,
DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend
FROM
yeardates a
LEFT JOIN
available_dates b
ON(a.yeardate BETWEEN b.start_date AND b.end_date)
OR
(DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date)
WHERE
b.date_id IS NULL AND WEEKDAY(a.yeardate)=5;
在我的情况下,这些块是7天,星期六到星期六 - 所以我在查询中添加了第二个WHERE
子句,这样我就可以在星期六的星期六到每个星期六的星期六块区分开,这发生一个在另一个之后。
所以而不是:
+------------+------------+
| blockstart | blockend |
+------------+------------+
| 2012-01-01 | 2012-01-08 |
| 2012-01-02 | 2012-01-09 |
| 2012-01-03 | 2012-01-10 |
| 2012-01-04 | 2012-01-11 |
我明白了:
+------------+------------+
| blockstart | blockend |
+------------+------------+
| 2012-01-07 | 2012-01-14 |
| 2012-01-14 | 2012-01-21 |
| 2012-01-21 | 2012-01-28 |
| 2012-01-28 | 2012-02-04 |
完全 我需要什么。再次感谢Zane的回答。
答案 0 :(得分:2)
将您的问题理解为检索当前和下一年的所有7天间隔块,其范围与available_dates
表中已存在的任何间隔块不重叠:
要处理当前和明年的所有日子,我们必须创建一个单独的表格(yeardates
),其中包含当前和明年所有日期的DATE
秒。这将有助于我们在检索查询中进行OUTER JOIN
操作。
用于定义yeardates
表并插入日期的代码:
CREATE TABLE yeardates
(
yeardate DATE NOT NULL,
PRIMARY KEY (yeardate)
) ENGINE = MyISAM;
DELIMITER $$
CREATE PROCEDURE PopulateYear(IN inputyear INT)
BEGIN
DECLARE i INT;
DECLARE i_end INT;
SET i = 1;
SET i_end = CASE WHEN inputyear % 4 THEN 365 ELSE 366 END;
START TRANSACTION;
WHILE i <= i_end DO
INSERT INTO yeardates VALUES (MAKEDATE(inputyear, i));
SET i = i + 1;
END WHILE;
COMMIT;
END$$
DELIMITER ;
CALL PopulateYear(2012);
CALL PopulateYear(2013);
然后创建该表并包含当前和下一年的所有日期。如果我们需要在接下来的几年中插入日期,只需再次CALL
该过程,并将年份作为参数(例如2014年,2015年等)。
然后我们可以获得在available_dates表中不重叠块的7天块:
SELECT
a.yeardate AS blockstart,
DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend
FROM
yeardates a
LEFT JOIN
available_dates b ON
(a.yeardate BETWEEN b.start_date AND b.end_date)
OR
(DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date)
WHERE
b.available_id IS NULL
根据所有属性的预订检索所有免费的7天块,但如果我们需要获取仅特定属性的7天免费块,我们可以使用:
SELECT
a.yeardate AS blockstart,
DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend
FROM
yeardates a
LEFT JOIN
(
SELECT *
FROM available_dates
WHERE property_id = <property_id here>
) b ON
(a.yeardate BETWEEN b.start_date AND b.end_date)
OR
(DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date)
WHERE
b.available_id IS NULL
<property_id here>
是property_id。我们甚至可以通过简单地将其更改为WHERE property_id IN (<comma sep'd list of property_ids here>)
来基于多个属性进行选择。
答案 1 :(得分:0)
我认为你已经倒退了。
除非已预订,否则所有日期都可能可用,记录数据库中已预订的内容并将其从结果中删除