2016-10-27 14 views
-2

私は長い間この問題に取り組んでいたので、質問があり、うまくいけば誰かが助けることができます。oracle sql計算を解決する時間

タスクが有効期限切れになる分の残りの列があり、現在のsysdate日から開始する営業日の期間内にこのタスクが期限切れになることを計算したい場合は、平日09:00〜17:00とします。

| Task No | Minutes Remaining | Expiration date | 
| Task1  | 1800    | 27-10-16 9:45 AM | 
| Task2  | 3400    | 28-10-16 9:45 AM | 
| Task3  | 400    | 29-10-16 9:45 AM | 
| Task4  | 180    | 30-10-16 9:45 AM | 
| Task5  | 8400    | 31-10-16 9:45 AM | 
| Task6  | 5000    | 1-11-16 9:45 AM | 
+0

いくつかのサンプルの入力データとどのようなあなたは結果があることを期待しているを入力してください。 – Boneist

+0

質問を追加情報で更新してください。データベースや要件を見ることができないので、問題を実証するためにできるだけ多くの情報を提供する必要があります。 – Boneist

+0

いいえ、あなたの質問を編集する必要があります( 'sql'と' oracle11g'タグの下にあなたの質問を見るなら、 'edit edit'をクリックして'そこ。そうすれば、あなたはそれをより良くフォーマットすることができます。 – Boneist

答えて

1

これは楽しい問題でした。要約すると、測定を開始する日付(Oracleには常に時刻が含まれています)と、最初の時間(分)が与えられます。有効期限(日時はいつもと同じです)を見つける必要があります。これは「時計開始日」に分数を加えて計算されますが、時計は営業時間内にのみ実行する必要があります。 17、月曜日から金曜日のみ(週末は除く)。

「残りの分」が0の場合、有効期限は就業時間内にある場合は「時計始動」日付と同じでなければなりません。そうでない場合は翌営業日に午前9時です。

解決策を理解するには、2つの部分に分解しましょう。まず、非常に特殊なケースを考えましょう。月曜日の午前9時に「時計が始まります」。次に、2400の整数倍(1週間に5 * 8 * 60 = 2400分)に残りの分を加え、残りの分(480分〜作業日)から480の倍数に加えて、もしあれば。次に、有効期限は「時計始動」の日付に加えて、数週間に加えて多くの終日(0と4の間)に加えて残りの分を加えたものです。 1つの例外的な場合:「残りの分」が480分の正確な倍数である場合、有効期限は特定の就業日に午後5時であり、翌営業日に午前9時ではない。これには、数式で特別な処理が必要です。このすべては外側のクエリ(以下のソリューションの一番下)で行われます。

次に、この特殊なケースに一般的なケースを減らす必要があります。これは、ソリューション内のサブクエリprepで行われます。私は週の初めに月曜日の午前9時から経過した作業分だけ「残りの分」を増やします。これは比較的単純な計算です。 「時計開始」の日付が金曜日の午後5時(または土曜日または日曜日の午後)の後である場合は、2400分(フルワーキング週間)を追加する必要があります。

解決策では、さまざまな「クロック開始」日付、dt、残りの分数はrmです。私はさまざまな状況をテストしましたが、解決策は正しいと思いますが、より多くのデータをテストすることができます(私がテストに含まなかった他の状況)。

with 
    inputs (task, min_rem, dt) as (
select 'Task1', 1800, to_date('27-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task2', 3400, to_date('28-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task3', 400, to_date('29-10-16 3:45 AM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task4', 180, to_date('30-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task5', 8400, to_date('31-10-16 9:45 PM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task6', 5000, to_date('01-11-16 5:00 PM', 'dd-mm-yy hh:mi AM') from dual union all 
select 'Task7', 0, to_date('01-12-16 5:00 PM', 'dd-mm-yy hh:mi PM') from dual 
    ), 
    prep (task, min_rem, dt, adj_min, adj_dt) as (
     select task, min_rem, dt, 
       min_rem + case when dt > trunc(dt, 'iw') + 5 + 17/24 then 2400 
          else (trunc(dt) - trunc(dt, 'iw')) * 480 + 
            least(480, greatest(0, 1440 * (dt - trunc(dt) - 9/24))) 
         end, 
       trunc(dt, 'iw') + 9/24 
    from inputs 
    ) 
select task, min_rem, dt, 
     adj_dt + 7 * trunc(adj_min/2400) 
       + case when adj_min/480 = trunc(adj_min/480) 
          then mod(adj_min, 2400)/480 - 1 + 8/24 
        else trunc(mod(adj_min, 2400)/480) + mod(adj_min, 480)/1440 
       end as expiration 
from prep 
order by task 
; 

出力

TASK  MIN_REM DT     EXPIRATION  
----- ---------- ----------------- ----------------- 
Task1  1800 27-10-16 09:45 AM 01-11-16 03:45 PM 
Task2  3400 28-10-16 09:45 AM 08-11-16 10:25 AM 
Task3  400 29-10-16 03:45 AM 31-10-16 03:40 PM 
Task4  180 30-10-16 09:45 AM 31-10-16 12:00 PM 
Task5  8400 31-10-16 09:45 PM 24-11-16 01:00 PM 
Task6  5000 01-11-16 05:00 PM 16-11-16 12:20 PM 
Task7   0 01-12-16 05:00 PM 01-12-16 05:00 PM 

7 rows selected