2

PHP/MySQL で予約システムを作成しています。

月を選択し、予約の長さを選択し、その月内に指定された長さの期間が利用可能な (つまり、予約済みとしてマークされていない) 期間を見つけられるようにしたいと考えています。

日付のテーブルを作成することから始めました。各日には、予約されているかどうかを示すフィールドと日付があります。2 つのテーブルは次のとおりです。

CREATE TABLE `day` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `date` date NOT NULL,
  `booking` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

CREATE TABLE `booking` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `start` date DEFAULT NULL,
  `end` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

これまでのところ、1 か月のうち予約されていない日数を数えることはできましたが、7 日連続して予約されているとは限りません。

SELECT  
    EXTRACT(YEAR FROM date) as year,
    EXTRACT( MONTH FROM date) as month,
    count(day.id)
FROM
    day
WHERE booking IS NULL
GROUP BY year, month

この時点で、特定の月のすべての日をロードし、PHP でそれらを繰り返し処理して数値を作成することを検討していますが、それはちょっとばかげていて非効率的です。この情報を MySQL から直接見つける方法を提案する人はいますか?

4

2 に答える 2

2

2012 年 7 月に少なくとも 7 日間の範囲が必要であると仮定すると、次のようになります。

SELECT
  DATE_FORMAT(start, '%Y-%m-%d') start,
  MAX(days) AS days,
  DATE_FORMAT(start + INTERVAL MAX(days) - 1 DAY, '%Y-%m-%d') end
FROM (  
  SELECT
    d2.`date` start,
    (@days := IF(IFNULL(d2.booking, 0) = 0, @days + 1, 1)) AS days
  FROM
    (SELECT @days := 1) a,
    day d1
  LEFT JOIN  
    day d2 on d2.`date` = d1.`date` + INTERVAL 1 DAY
  WHERE
    IFNULL(d1.booking, 0) = 0
) d1
GROUP BY
  start
HAVING
  (
    EXTRACT(YEAR_MONTH FROM start) = 201207 OR
    EXTRACT(YEAR_MONTH FROM (start + INTERVAL MAX(days) - 1 DAY)) = 201207
  ) AND
  days >= 7
ORDER BY
  start

次の出力が生成されます。

|      START | DAYS |        END |
----------------------------------
| 2012-06-25 |   13 | 2012-07-07 |
| 2012-06-26 |   12 | 2012-07-07 |
| 2012-06-27 |   11 | 2012-07-07 |
| 2012-06-28 |   10 | 2012-07-07 |
| 2012-06-29 |    9 | 2012-07-07 |
| 2012-06-30 |    8 | 2012-07-07 |
| 2012-07-01 |    7 | 2012-07-07 |
| 2012-07-23 |    8 | 2012-07-30 |
| 2012-07-24 |    7 | 2012-07-30 |

条項

(  
    EXTRACT(YEAR_MONTH FROM start) = 201207 OR
    EXTRACT(YEAR_MONTH FROM (start + INTERVAL MAX(days) - 1 DAY)) = 201207
) 

範囲が前月または翌月に及ぶ場合でも、すべての範囲を含めるために使用されます。1 か月だけに収まる範囲が必要な場合は、次を使用します。

EXTRACT(YEAR_MONTH FROM start) = 201207 AND
EXTRACT(YEAR_MONTH FROM (start + INTERVAL MAX(days) - 1 DAY)) = 201207

インタラクティブなデモについては、http://sqlfiddle.com/#!2/4e36a/4を参照してください。

于 2012-10-01T04:47:23.077 に答える
0

これを試すことができます:

SELECT EXTRACT(YEAR_MONTH FROM date) AS year_month, COUNT(*) AS cnt
FROM day
LEFT JOIN booking ON booking.start <= day.date + INTERVAL 6 DAY
                  AND booking.end >= day.date
WHERE booking.start IS NULL
GROUP BY year_month

アイデアは、その日から始まる 7 日間の範囲と重複するday行がない行を探しているということです。booking

于 2012-09-30T19:02:07.680 に答える