我有一个难题,希望有人能帮我解决
我有一张公寓列表。每个列表都有一个或多个“不可用”日期单独存储在另一个表中,我们将其称为“off_days”。例如9 月 1 日至 4 日期间不可用的列表将在“off_days”表中包含 4 个条目,每天一个。
我正在寻找最有效的方法来搜索(最好是在数据库级别)两个日历日之间至少有 N 个连续可用天的列表(“可用”是指不在“off_days”表中的任何一天)特别列出)。例如“显示 9 月份至少有 5 个连续可用天数的所有列表”
我一直在思考如何在现实世界中解决这个问题(通过查看标有 X 的日历并扫描空闲 block ),并开始考虑使用二进制来表示可用/不可用的天数。即对于给定的一周,0111001 ( = 57) 会告诉我该周最多有连续三天可用。
这个question一旦我有了给定日期范围的二进制数,这似乎是一个好的开始,但现在我陷入了如何在给定日期范围动态计算该数字的问题上,再次,在数据库级别......有什么想法吗?或者对这种方法或另一种方法的想法?
最佳答案
公寓可在休息日空档使用。这意味着您想知道每个序列的间隙有多大,lag()
函数可以为您提供以下信息:
select od.*,
lag(unavailable) over (partition by apartmentid order by unavailable) as prev_una
from offdays od;
实际天数是不可用天数与前一个天数之间的差值减 1。现在,假设两个日历日为 v_StartDate
和 v_EndDate
。现在你基本上可以得到你想要的东西:
select od.*,
((case when unavailable is NULL or unavailable > v_EndDate
then v_EndDate + 1 else unavailable
end) -
(case when prev_una is null or prev_una < v_StartDate
then v_StartDate - 1 else prev_una
end) - 1
) as days_available
from (select od.*, lag(unavailable) over (partition by apartmentid order by unavailable) as prev_una
from offdays od
) od
order by days_available desc;
case
逻辑本质上是在句点之前和之后添加停止日期。
这并不完全完整,因为它存在边界问题:当公寓不在休息日
时会出现问题,当不可用时段超出范围时会出现问题。让我们用union all
和一些过滤来解决这个问题:
select od.*,
((case when unavailable is NULL or unavailable > v_EndDate
then v_EndDate + 1 else unavailable
end) -
(case when prev_una is null or prev_una < v_StartDate
then v_StartDate - 1 else prev_una
end) - 1
) as days_available
from (select od.apartmentId, unavailable,
lag(unavailable) over (partition by apartmentid order by unavailable) as prev_una
from offdays od
where od.unavailable between v_StartDate and v_EndDate
union all
select apartmentid, NULL, NULL
from apartments a
where not exists (select 1
from offdays od
where od.apartmentid = a.apartmentid and
od.unavailable between v_StartDate and v_EndDate
)
) od
order by days_available desc;
关于sql - 查找给定日期范围、持续时间和不可用日期列表的可用公寓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25342170/