0

我的数据库中有一个“假期”表,其中包含假期的日期范围,用两列定义:开始和结束。

Holidays (id, name, start, end)

现在,如果我输入两个日期(从和到),我想列出所有不在节假日的日期。

假设假期是从2012/06/052012/06/20,我要求:

  1. 从=2012/06/01,到=2012/06/10;结果将是01、02、03、04
  2. 从=2012/06/01,到=2012/06/22;结果将是01、02、03、04、21、22
  3. 从=2012/06/15,到=2012/06/22;结果将是21, 22

但是我无法弄清楚如何在不访问数据库的情况下获取这个“开放”天的列表,而不是在从->到的范围内请求的每一天。

我怎么能那样做?

4

3 回答 3

0

有很多解决方案,但这在很大程度上取决于您在数据库中有多少条目以及您执行了多少请求。如果您提出很多请求,则可以执行以下操作:

-> create a boolean array that will determine if a day is holiday or not;
   first element points to some predefined date (e.g. 1.1.2012), 
   second element to 2.1.2012, etc.
-> initialize an array to 0
-> for each holiday you do
  -> make a for loop initialized with holiday start date and
     expression for each pass: current date = holiday start date + 1 day
    -> covert the current date to index (number of days since start date - 1.1.2012)
    -> set the array[index] to 1

现在你应该有一个简单的数组,其中 0 代表非节假日,1 代表节假日

对于您现在执行的每个查询(请求)

-> for loop that goes from request start date to request end date
   -> convert the current date to index (number of days since 1.1.2012)
   -> check if array[index] is 0 or 1

但请记住,该解决方案适用于许多查询(请求)。如果您必须为每个请求执行第一部分,那么此解决方案没有意义,最好编写一个 sql 查询。

于 2012-06-06T12:59:42.600 回答
0

这是我最终如何做到的,它似乎有效:

SELECT start, end FROM holidays WHERE
(start > :START AND end < :END) OR
(start < :START AND end > :END) OR
(start BETWEEN :START AND :END) OR
(end BETWEEN :START AND :END);

这仅返回我:START/:END日期至少接触一个假期的行。它涵盖了这些可能性:

  1. start 在假期开始之前,如果在假期结束之前结束(之前,在)
  2. start 在假期开始之前,如果在假期结束之后结束(之前,之后)
  3. start 在假期开始之后,如果在假期结束之前结束(in,in)
  4. start 在假期开始之后,如果在假期结束之后结束(in,after)

我想我涵盖了所有的可能性。

然后我遍历结果并为每一行构建一个从start到的日期数组。end

最后,我循环遍历我的初始范围日期,如果其中一个日期在数组中,我将它们删除。

于 2012-06-06T14:42:24.127 回答
0

这是一个解决方案,可以在单个(尽管有点复杂)SQL 语句(这是 Oracle)中为您提供解决方案:

with all_days as (
  select :start_date + (level - 1) dt
   from dual
  connect by :start_date + (level - 1) <= :end_date
)
select a.dt 
  from all_days a
 where not exists (
    select 1 
      from holidays h
     where h.start_dt <= a.dt and h.end_dt >= a.dt
)
order by a.dt

例如,假设以下假期表:

NAME           START_DT                  END_DT                    
-------------- ------------------------- ------------------------- 
Test Holiday 1 07-JUN-12                 13-JUN-12                 
Test Holiday 2 17-JUN-12                 18-JUN-12                 

并使用 5th June as:start_date和 20th June as :end_date,您将获得以下输出:

DT                        
------------------------- 
05-JUN-12                 
06-JUN-12                 
14-JUN-12                 
15-JUN-12                 
16-JUN-12                 
19-JUN-12                 
20-JUN-12                

(它提供了一个范围内的日期减去假期表中一个范围内指定的任何日期)。

希望有帮助。

于 2012-06-06T14:42:26.350 回答