2017-12-20 19 views
3

次の表があるとします。 毎月の遅延を別々に計算する方法を教えてください。月ごとのレコードの差分日時を計算する

Req start_dt end_dt 
1 1/2/2017 3/5/2017 
2 5/2/2017 7/6/2017 

結果は次の表のようになります。

Req start_dt end_dt  delay MM 
1 1/2/2017 3/5/2017 30  1 
1 1/2/2017 3/5/2017 28  2 
1 1/2/2017 3/5/2017 5  3 
2 5/2/2017 7/6/2017 30  5 
2 5/2/2017 7/6/2017 30  6 
2 5/2/2017 7/6/2017 6  7 
+0

何ロジックあなたはその結果を取得するために使用していますか?あなたはそれを達成しようとしましたか? –

+0

シンプルな日数の場合は、word:date1 - date2を指定します。月の違いを得るために、MONTHS_BETWEEN関数があります。 – Alex

+0

遅延とMMの列の日付と値の間に関係は実際には分かりません。最後の3行は正確に同じ日付を持ち、遅延値とMM値が異なります。あなたの論理は何ですか? –

答えて

2

あなたは、相関階層問合せでそれを行うことができます。

SQL Fiddle

O racle 11gのR2スキーマのセットアップ

CREATE TABLE table_name (Req, start_dt, end_dt) AS 
SELECT 1, DATE '2017-01-02', DATE '2017-03-05' FROM DUAL UNION ALL 
SELECT 2, DATE '2017-05-02', DATE '2017-07-06' FROM DUAL; 

クエリ1

SELECT t.*, 
     LEAST(LAST_DAY(d.COLUMN_VALUE), t.end_dt) 
     - GREATEST(d.COLUMN_VALUE, t.start_dt) + 1 AS delay, 
     EXTRACT(MONTH FROM d.COLUMN_VALUE) AS MM 
FROM table_name t 
     CROSS JOIN 
     TABLE(
     CAST(
      MULTISET(
      SELECT ADD_MONTHS(TRUNC(t.start_dt, 'MM'), LEVEL - 1) 
      FROM DUAL 
      CONNECT BY LEVEL <= MONTHS_BETWEEN(t.end_dt, TRUNC(t.start_dt, 'MM')) + 1 
      ) AS SYS.ODCIDATELIST 
     ) 
     ) d 

Results

| REQ |    START_DT |    END_DT | DELAY | MM | 
|-----|----------------------|----------------------|-------|----| 
| 1 | 2017-01-02T00:00:00Z | 2017-03-05T00:00:00Z | 30 | 1 | 
| 1 | 2017-01-02T00:00:00Z | 2017-03-05T00:00:00Z | 28 | 2 | 
| 1 | 2017-01-02T00:00:00Z | 2017-03-05T00:00:00Z |  5 | 3 | 
| 2 | 2017-05-02T00:00:00Z | 2017-07-06T00:00:00Z | 30 | 5 | 
| 2 | 2017-05-02T00:00:00Z | 2017-07-06T00:00:00Z | 30 | 6 | 
| 2 | 2017-05-02T00:00:00Z | 2017-07-06T00:00:00Z |  6 | 7 | 
+0

驚くべきことにはうまく動作します。ありがとうまで私はあなたのクエリがどのように動作しているか理解できません。私はそれを理解しようとしています。再度、感謝します。 – Nawaf

+1

@ Nawafテーブル内の各行について、階層クエリを評価して範囲をオーバーラップさせる月の配列を生成し、関連する行に戻ってそれを 'CROSS JOIN'して、各範囲内の各月に1行。 – MT0

+0

end_dtがnullの場合に遅延を計算する方法。 – Nawaf

2

あなたは、開始と終了ヶ月間の中間ヶ月と部分的な範囲のための完全な範囲で、複数ヶ月にあなたの日付の範囲を分割する必要があります。それを行う1つの方法はrecursive subquery factoring

with rcte (req, start_dt, end_dt, period_start_dt, period_end_dt) as (
    select req, start_dt, end_dt, start_dt, 
    case when trunc(end_dt, 'MM') = trunc(start_dt, 'MM') then end_dt 
     else last_day(start_dt) end 
    from your_table 
    union all 
    select req, start_dt, end_dt, add_months(trunc(period_start_dt, 'MM'), 1), 
    case when trunc(end_dt, 'MM') = add_months(trunc(period_start_dt, 'MM'), 1) then end_dt 
     else last_day(add_months(trunc(period_start_dt, 'MM'), 1)) end 
    from rcte 
    where trunc(end_dt, 'MM') > trunc(period_start_dt, 'MM') 
) 
select req, start_dt, end_dt, period_start_dt, period_end_dt, 
    period_end_dt - period_start_dt + 1 as delay, 
    extract(month from period_start_dt) as mm 
from rcte 
order by req, period_start_dt, period_end_dt; 

     REQ START_DT END_DT  PERIOD_STA PERIOD_END  DELAY   MM 
---------- ---------- ---------- ---------- ---------- ---------- ---------- 
     1 2017-01-02 2017-03-05 2017-01-02 2017-01-31   30   1 
     1 2017-01-02 2017-03-05 2017-02-01 2017-02-28   28   2 
     1 2017-01-02 2017-03-05 2017-03-01 2017-03-05   5   3 
     2 2017-05-02 2017-07-06 2017-05-02 2017-05-31   30   5 
     2 2017-05-02 2017-07-06 2017-06-01 2017-06-30   30   6 
     2 2017-05-02 2017-07-06 2017-07-01 2017-07-06   6   7 

で再帰CTEは、あなたのテーブルから初期データを取得するアンカー部材を有し、第1の期間の開始と終了を計算します。期間開始は元の範囲開始日です。期間終了は範囲終了日(同じ月の場合)またはその月の終わりです。

再帰メンバは、アンカーからの値を使用し、次の月の冒頭に開始し、元の範囲の終了日またはその月の終わりに終了する新しい期間を生成します。

期間の開始日と終了日を取得したら、通常の日付減算を使用して差額を計算するのは簡単です。


少し単純計算のため、(あなたがそれらをしたくない場合だけで、最終的な選択リストから削除し、私は試してみて、それが少し明確にするために、出力期間の開始/終了日を残してきました。)期間の開始/終了日:

with rcte (req, start_dt, end_dt, period_start_dt, period_end_dt) as (
    select req, start_dt, end_dt, start_dt, least(end_dt, last_day(start_dt)) 
    from your_table 
    union all 
    select req, start_dt, end_dt, add_months(trunc(period_start_dt, 'MM'), 1), 
    least(end_dt, last_day(add_months(trunc(period_start_dt, 'MM'), 1))) 
    from rcte 
    where trunc(end_dt, 'MM') > trunc(period_start_dt, 'MM') 
) 
select req, start_dt, end_dt, 
    period_end_dt - period_start_dt + 1 as delay, 
    extract(month from period_start_dt) as mm 
from rcte 
order by req, period_start_dt, period_end_dt; 

     REQ START_DT END_DT   DELAY   MM 
---------- ---------- ---------- ---------- ---------- 
     1 2017-01-02 2017-03-05   30   1 
     1 2017-01-02 2017-03-05   28   2 
     1 2017-01-02 2017-03-05   5   3 
     2 2017-05-02 2017-07-06   30   5 
     2 2017-05-02 2017-07-06   30   6 
     2 2017-05-02 2017-07-06   6   7 
+0

あなたの努力と明確化のためにありがとうございます。残念ながら、コードは動作していません。私は再び修正しようとします。再度、感謝します。 – Nawaf

+0

「うまくいきません」もあまり役に立ちません。それはあなたが与えたサンプルデータで動作するようです。 –

関連する問題