0

データベースに「Holidays」というテーブルがあります。このテーブルには、休日の日の範囲が含まれており、開始と終了の2つの列で定義されています。

Holidays (id, name, start, end)

ここで、入力に2つの日付(fromとto)がある場合、休日にないすべての日付をリストしたいと思います。

休日が2012/06/05から2012/06/20であると仮定し、次のように要求します。

  1. from = 2012/06/01、to = 2012/06/10; 結果は01、02、03、04になります
  2. from = 2012/06/01、to = 2012/06/22; 結果は01、02、03、04、21、22になります
  3. from = 2012/06/15、to = 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これは、my / :ENDdatesが少なくとも1つの休日に接触する行のみを返します。それはそれらの可能性をカバーしています:

  1. 開始は休日の開始前であり、休日の終了前の場合は終了(before、in)
  2. 開始は休日の開始前であり、休日の終了後(前、後)の場合は終了
  3. 開始は休日の開始後、終了は休日の終了前(in、in)
  4. 開始は休日の開始後、終了は休日の終了後(in、after)

私はそれですべての可能性をカバーしていると思います。

次に、結果をループして、行ごとにからstartまでの日付の配列を作成します。end

そして、最終的に最初の範囲の日付をループします。それらの日付の1つが配列にある場合は、それらを削除します。

于 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                 

また、6月5日をとして:start_date、6月20日をとして使用: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 に答える