私はここで挑戦的な課題に直面しており、その日は一日を過ごしました。手順でしか解決できませんでしたすべてのプロジェクトで実行するには時間がかかりすぎる。SQLで祝日、例外、週末をスキップする指定日にN営業日を追加するDB2
私は(関数や手続きなし)可能な場合は、単一のクエリでそれを解決したいと思います。
ここでは、プログラミング言語やSQL関数/プロシージャでこれをやっている質問がいくつかあります(これもまた解決しました)。それだけでSQL
背景情報とそれを解決することができるのであれば、私は聞いてるのよです:
project
テーブルphase
テーブルholiday
テーブルdayexception
休日または週末の日をキャンセルする(作業日としての日付を作成する)、プロジェクトに関連付けられているテーブル- プロジェクトは0-N個のフェーズES
- 相
start date
を持ち、duration
と(システムが必要とする)draworder
- 営業日週末と休日ではないではありませんすべての日です(その日付が
dayexception
テーブル内にある場合には例外がある)
project | phase(s) | Dayexception | Holiday
id | id pid start duration draworder | pid date | date
1 | 1 1 2014-01-20 10 0 | 1 2014-01-25 | 2014-01-25
| 2 1 2014-02-17 14 2 | |
project id 1
とphase id 1
ためENDDATE
が実際に2014-01-31
目を参照してくださいです:
は、この次のシナリオを検討しますEは、以下のデータを生成した: 以下のデータの日付(及び今後)dd/mm/yyyy
(ブラジル形式)としてフォーマットされ、値をN
私はすべてでビューdaysOfYear
を作成し、上記データを生成するnull
proj pha start day weekday dayexcp holiday workday
1 1 20/01/2014 20/01/2014 2 N N 1
1 1 20/01/2014 21/01/2014 3 N N 1
1 1 20/01/2014 22/01/2014 4 N N 1
1 1 20/01/2014 23/01/2014 5 N N 1
1 1 20/01/2014 24/01/2014 6 N N 1
1 1 20/01/2014 25/01/2014 7 25/01/2014 25/01/2014 1
1 1 20/01/2014 26/01/2014 1 N N 0
1 1 20/01/2014 27/01/2014 2 N 27/01/2014 0
1 1 20/01/2014 28/01/2014 3 N N 1
1 1 20/01/2014 29/01/2014 4 N N 1
あります2014年から2015年までの日数(それは大きくても小さくても、年回しのケースでは2年で作成されます)をCTEクエリで確認できます。そして、次のSELECT文:
select ph.project_id proj,
ph.id phase_id pha,
ph.start,
dy.curday day,
dy.weekday, /*weekday here is a calling to the weekday function of db2*/
doe.exceptiondate dayexcp,
h.date holiday,
case when exceptiondate is not null or (weekday not in (1,7) and h.date is null)
then 1 else 0 end as workday
from phase ph
inner join daysofyear dy
on (year(ph.start) = dy.year)
left join dayexception doe
on (ph.project_id = doe.project_id
and dy.curday = truncate(doe.exceptiondate))
left join holiday h
on (dy.curday = truncate(h.date))
where ph.project_id = 1
and ph.id = 1
and dy.year in (year(ph.start),year(ph.start)+1)
and dy.curday>=ph.start
and dy.curday<=ph.start + ((duration - 1) days)
order by ph.project_id, start, dy.curday, draworder
このシナリオを解決するためには、私は次のクエリを作成:
select project_id,
min(start),
max(day) + sum(case when workday=0 then 1 else 0 end) days as enddate
from project_phase_days /*(view to the above select)*/
これは正しく返します。
proj start enddate
1 20/01/2014 31/01/2014
私は解決できなかった問題があります最後の終了日(max(day)
)に追加する日数(非稼働日sum(case when workday=0 then 1 else 0 end) days
)が週末または休日または例外である場合。私のクエリは
proj start enddate
81 14/04/2014 23/04/2014
戻ります上記のデータと
proj pha start day weekday dayexcp holiday workday
81 578 14/04/2014 14/04/2014 2 N N 1
81 578 14/04/2014 15/04/2014 3 N N 1
81 578 14/04/2014 16/04/2014 4 N N 1
81 578 14/04/2014 17/04/2014 5 N N 1
81 578 14/04/2014 18/04/2014 6 N 18/04/2014 0
81 578 14/04/2014 19/04/2014 7 N 0
81 578 14/04/2014 20/04/2014 1 N 20/04/2014 0
/*the below data I added to show the problem*/
81 578 14/04/2014 21/04/2014 2 N 21/04/2014 0
81 578 14/04/2014 22/04/2014 3 N 1
81 578 14/04/2014 23/04/2014 4 N 1
81 578 14/04/2014 24/04/2014 5 N 1
しかし、正しい結果は次のようになります。
は(以下、位相のための期間は7ある)次のシナリオを参照してください。 enddate
を24/04/2014
としています。これは、前のデータセットで確認できるように、最終日の後の日が週末や休日(またはその問題の例外)である場合、クエリには考慮されないためです。私の時間外にある21/04/2014
日も休日です。
私はまた、期間が終わるまで反復ごとに日を追加するphase
テーブルの上にCTEを作成しようとしましたが、DB2は私が上の左結合を追加できなくなるので、私はexceptions
もholidays
を追加することができませんでしたCTE再帰。
with CTE (projectid, start, enddate, duration, level) as (
select projectid, start, start as enddate, duration, 1
from phase
where project_id=1
and phase_id=1
UNION ALL
select projectid, start, enddate + (level days), duration,
case when isWorkDay(enddate + (level days)) then level+1 else level end as level
from CTE left join dayexception on ...
left join holiday on ...
where level < duration
) select * from CTE
PS:このように上記のクエリがあるため、DB2の制限のとisWorkDay
だけで(それはdayexceptionと休日テーブル値の場合である)の例として、ある動作しません。
ご不明な点がございましたら、コメントにお尋ねください。 ご協力いただければ幸いです。ありがとう。
実際はかなり良いアイデアです。しかし、 'ID'カラムは必要ありません。RDBMに応じて、' ROW_NUMBER'、 'ROWID'などを使うことができます。私が好きなアイデアは、仕事の日のテーブル/ビューを持つことです。私は、非稼働日や例外を除外/追加することができます。ありがとうございました。私は月曜日に仕事に戻り、私はこの経験を共有します。 +1 –
スコープのクリープの細目をまっすぐに保つことができれば行番号。 – danny117
こんにちは@ danny117。私は最終的な解決策を追加しました。私はあなたの答えを私の問題を解決するための中心的なアイデアを与えたものとしてマークします。ありがとうございました。 –