MySQL可用性日历 - 计算免费日期的方法?

时间:2012-06-14 16:08:40

标签: php mysql calendar

我正在使用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的回答。

2 个答案:

答案 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)

我认为你已经倒退了。

除非已预订,否则所有日期都可能可用,记录数据库中已预订的内容并将其从结果中删除