'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 晚最便宜的时间。
我有:
- table 个日期
- table 个房间,每个房间都有唯一的 ID
- a table 个具有房间 ID、开始和结束日期以及价格的价格(价格在日期范围内设置,然后每个日历年都有一个标准价格,该价格用于任何不在设定费率日期范围之一内的日期)
- table 个具有房间 ID、开始和结束日期的预订。
使用 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 晚拉回一个结果,而是带回两个:
- 5 月 25 日 - 31 日(6 晚)
- 6 月 1 日至 14 日(13 晚)
我不知道它为什么会这样或如何解决它,但我想如果我能找到这个问题的解决方案,我的问题的前半部分就会得到解决。第二个是通过查看房价 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`;
编辑:我已将标题从 "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 晚最便宜的时间。
我有:
- table 个日期
- table 个房间,每个房间都有唯一的 ID
- a table 个具有房间 ID、开始和结束日期以及价格的价格(价格在日期范围内设置,然后每个日历年都有一个标准价格,该价格用于任何不在设定费率日期范围之一内的日期)
- table 个具有房间 ID、开始和结束日期的预订。
使用 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 晚拉回一个结果,而是带回两个:
- 5 月 25 日 - 31 日(6 晚)
- 6 月 1 日至 14 日(13 晚)
我不知道它为什么会这样或如何解决它,但我想如果我能找到这个问题的解决方案,我的问题的前半部分就会得到解决。第二个是通过查看房价 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`;