'Arftul Software' 'Find sequence starts and ends' 有日期

'Arftul Software' 'Find sequence starts and ends' with Dates

编辑:我已将标题从 "Find Cheapest Available Dates Based on Min and Max Date and Duration - MySQL PHP" 更改为使问题更通用,希望遇到此问题的其他人能够找到解决方案。以下是我原来问题的全部内容,但在这里我会 re-write 因为现在我明白了问题是什么,我可以更好地解释它。我自己也添加了答案。

RE-WRITTEN 问题

Artful Software 网站有一个名为“Find sequence starts and ends”的查询示例,我希望使用它来查找有空房的日期序列,但由于某种原因,查询中断了从一个月到下个月的连续结果。例如,如果一个房间在 6 月 28 日和 7 月 3 日之间有空房,则会 return 两个结果:

28th - 30th June
1st - 3rd July

什么时候应该 return 这些日期只有一个结果,因为它们是连续的。为什么会发生这种情况,我该如何预防?

原始详细问题

给定最短到达日期、最长离开日期和停留时间,我想找出该时间段内哪些房间可用,以及return最便宜的日期。

例如。用户希望在 5 月 25 日至 6 月 30 日之间的任何时间入住 14 晚。首先,我需要检查我的哪些房间在 5 月 25 日至 6 月 30 日期间至少有连续 14 晚的可用住宿,然后对于有的每个房间,我想显示哪些日期是入住 14 晚最便宜的时间。

我有:

使用 artfulsoftware.com 处的示例(特别是 this one。向下滚动到 'Forum contributor "laptop alias" posted this solution' 部分以查看我使用的连接示例)我想出了到目前为止。这是我试图找出哪些房间至少有正确数量的连续可用日期;它不会尝试找到最便宜的:

SELECT r.`id`
FROM `rooms` r
RIGHT JOIN(
  SELECT a.roomId, a.date AS startdate, MIN( c.date ) AS enddate, DATEDIFF(MIN( c.date ), a.date)+1 AS nights
  FROM (
    SELECT r.id AS roomId, d.date AS date
    FROM dates AS d
    CROSS JOIN rooms AS r WHERE
    NOT EXISTS ( SELECT id, roomId
      FROM bookings AS b
      WHERE d.date BETWEEN b.start_date AND b.end_date
      AND r.Id = roomId )
    AND d.date BETWEEN :minArr1 AND :maxDept1
  ) AS a

  LEFT JOIN(
    SELECT r.id AS roomId, d.date AS date
    FROM dates AS d
    CROSS JOIN rooms AS r WHERE
    NOT EXISTS (
      SELECT id, roomId
      FROM bookings AS b
      WHERE d.date BETWEEN b.start_date AND b.end_date
      AND r.Id = roomId
    )
    AND d.date BETWEEN :minArr2 AND :maxDept2
  ) AS b
  ON a.date = b.date + 1 AND a.roomId = b.roomId

  LEFT JOIN (
    SELECT r.id AS roomId, d.date AS date
    FROM dates AS d
    CROSS JOIN rooms AS r WHERE
    NOT EXISTS (
      SELECT id, roomId FROM bookings AS b
      WHERE d.date BETWEEN b.start_date AND b.end_date
      AND r.Id = roomId
    )
    AND d.date BETWEEN :minArr3 AND :maxDept3
  ) AS c
  ON a.date <= c.date AND a.roomId = c.roomId

  LEFT JOIN (
    SELECT r.id AS roomId, d.date AS date
    FROM dates AS d
    CROSS JOIN rooms AS r WHERE
    NOT EXISTS (
      SELECT id, roomId
      FROM bookings AS b
      WHERE d.date BETWEEN b.start_date AND b.end_date
      AND r.Id = roomId
    )
    AND d.date BETWEEN :minArr4 AND :maxDept4
  )AS d ON c.date = d.date - 1 AND c.roomId = d.roomId

  WHERE b.date IS NULL
  AND c.date IS NOT NULL
  AND d.date IS NULL
  GROUP BY a.date, a.roomId
)AS results
on results.roomId = r.Id
WHERE nights >= :n

现在我遇到的问题是,出于某种原因,当我们到达月底时,这会中断连续的约会。假设一个房间从 5 月 25 日到 6 月 14 日一直可用,而不是用 20 晚拉回一个结果,而是带回两个:

我不知道它为什么会这样或如何解决它,但我想如果我能找到这个问题的解决方案,我的问题的前半部分就会得到解决。第二个是通过查看房价 table 找到 returned 期间最便宜的 14 晚住宿,但一次只能做一件事。

事实证明,经过大量的摸索,解决方案很简单。 Artful Software 页面上的示例之所以有效,是因为他只处理序列号,而不是日期。为了使用日期,您必须更改 +1 和 -1 以便添加和减去日期。这是该站点的原始解决方案:

SELECT 
  a.id AS Start, 
  MIN( c.id ) AS End 
FROM tbl AS a
LEFT JOIN tbl AS b ON a.id = b.id + 1
LEFT JOIN tbl AS c ON a.id <= c.id
LEFT JOIN tbl AS d ON c.id = d.id - 1
WHERE b.id IS NULL 
  AND c.id IS NOT NULL
  AND d.id IS NULL
GROUP BY a.id; 

为了使这个适用于日期,只需使用:

SELECT 
  a.`date` AS Start, 
  MIN( c.`date` ) AS End 
FROM dates AS a
LEFT JOIN dates AS b ON a.`date` = DATE_ADD(b.`date`,INTERVAL 1 DAY)
LEFT JOIN dates AS c ON a.`date` <= c.`date`
LEFT JOIN dates AS d ON c.`date` = DATE_ADD(d.`date`,INTERVAL -1 DAY)
WHERE b.`date` IS NULL 
  AND c.`date` IS NOT NULL
  AND d.`date` IS NULL
GROUP BY a.`date`;