2

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テーブルと手順を使用して、必要な結果を得ることができました。私が行ったことは、可用性が設定されていない日付を表示する必要があるページが要求されたときに、PHPがプロシージャを呼び出して、の日付がない場合はさらに年の日付を追加しますCURYEAR()+2

次に、私の結果を取得するために、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ため、クエリに2番目の句を追加して、行ごとに1週間の土曜日から土曜日のブロックを次々に取得できるようにしました。

したがって、代わりに:

+------------+------------+
| 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にもう一度感謝します。

4

2 に答える 2

2

質問を次のように理解します。範囲がテーブルにすでに存在する間隔ブロックと重複しない、現在および来年の7日間の間隔ブロックをすべて取得しavailable_datesます。

現在および来年のすべての日を処理するには、現在および来年のすべての日のsを含む別のテーブル(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はどこにありますか<property_id here>。に変更するだけで、一度に複数のプロパティに基づいて選択することもできますWHERE property_id IN (<comma sep'd list of property_ids here>)

于 2012-06-14T19:39:20.900 に答える
0

私はあなたがそれを逆に持っていると思います。

予約されていない限り、すべての日付が利用可能である可能性があり、データベースに予約されたものを記録し、結果からそれらをノックアウトします

于 2012-06-14T16:12:41.140 に答える