2016-12-23 8 views
2

プロジェクトの予測予算に基づいて「将来の月」を取得するためのクエリを作成しています。返信先の行よりも多くの行を接続する

基本的に予測を行う予定の最終日(START_DATE)と今後の予定(END_DATE)を取っていますので、その間にすべてを数か月間で入力する必要があります。

私は「CONNECT BY」が多くの助けになることがわかった研究をいくつか行っています。それをSimplyfying

は、クエリは次のようになります。

SELECT  TO_CHAR (ADD_MONTHS (START_DATE, LEVEL - 1), 'fmMonth') 
    FROM (SELECT PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE 
      FROM PROJECTS 
      WHERE PROJECT_ID = 001) 
CONNECT BY LEVEL <= 
       MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'), 
           TRUNC (START_DATE, 'MM') 
          ) 
      * +1 

一つのプロジェクトを選択するときに、クエリが正常に動作しますいくつかまたはすべてのプロジェクト/行を選択するときに、しかし、クエリがより多くの行以外を分解し、返します期待される。

ソースデータは、このようなものを見て:私は予想よりトン以上ヶ月と年を取得するしかし、私が見ることを期待する何

PROJECT_ID | FORECAST_VALUE | START_DATE | END_DATE 
-----------+----------------+------------+----------- 
001  | 100   | 2017-01-01 | 2017-03-01 
002  | 200   | 2017-01-01 | 2017-05-01 
003  | 200   | 2017-10-01 | 2018-01-01 

この

PROJECT_ID | FORECAST_VALUE | FORECAST_YEAR | FORECAST_MONTH 
-----------+----------------+---------------+----------- 
001  | 100   | 2017   | JANUARY 
001  | 100   | 2017   | FEBRUARY 
001  | 100   | 2017   | MARCH 

002  | 200   | 2017   | JANUARY 
002  | 200   | 2017   | FEBRUARY 
002  | 200   | 2017   | MARCH 
002  | 200   | 2017   | APRIL 
002  | 200   | 2017   | MAY 

003  | 200   | 2017   | OCTOBER 
003  | 200   | 2017   | NOVEMBER 
003  | 200   | 2017   | DECEMBER 
003  | 200   | 2018   | JANUARY 

ようなものになるだろう。

どうすればこの問題を解決できますか?

ありがとうございます!

+1

は、単純なデータの高密度化問題のようですね。ソースデータと希望する結果のサンプルを常に投稿してください。簡単に言えば。ここに私が持っているものがあります。ここに私が欲しい出力があります。私が書いた質問です。 –

+0

@NicholasKrasnovありがとう!ちょうど私の質問にそれを加えました。 – dkg

+0

および実行中のOracleのバージョン –

答えて

0

簡単な方法は、あなたが1000ヶ月、言う、以下でもありませんと仮定して、数字の表を使用して、テーブルに参加することができます

select PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE, TO_CHAR (ADD_MONTHS (START_DATE, num - 1), 'fmMonth') 
from PROJECTS 
inner join (   
      select level as num 
      from dual 
      connect by level <= 1000 
      ) nums   
on (num -1 <= months_between(TRUNC (END_DATE, 'MM'), 
          TRUNC (START_DATE, 'MM')) ) 
order by 1, num 
1

あなたが入れ1以外の条件を持っていないので、 CONNECT BYでは、各レベルの各行は次のレベルでさらに多くの行を生成します(各レベルで各PROJECT_IDのトラッキングはありません)。行をPROJECT_ID = PRIOR PROJECT_IDでリンクする必要があります。しかし、これは "サイクル"につながります。 CONNECT BY...は、すべての列ではなく、PRIOR演算子のみの影響を受けた列を見てサイクルを検出します。無関係のPRIOR条件を追加することで、異なる行の異なる値を保証するサイクルを中断することができます。伝統的にはSYS_GUID()が使用されています。私はPROJECT_IDは、ベーステーブルPROJECTSで一意のキー(?おそらく主キー)であることを、当然のことながら、想定しています

SELECT  TO_CHAR (ADD_MONTHS (START_DATE, LEVEL - 1), 'fmMonth') 
    FROM (SELECT PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE 
      FROM PROJECTS 
      WHERE PROJECT_ID = 001) 
CONNECT BY LEVEL <= 
       MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'), 
           TRUNC (START_DATE, 'MM') 
          ) 
      * +1   -- whatever that means (copied from original post) 
     AND PROJECT_ID = PRIOR PROJECT_ID 
     AND PRIOR SYS_GUID() IS NOT NULL 

次のように

はあなたのクエリを変更します。

0

これを行う方法が1つあります。 start_dateと、最大でend_dateの間にすべてを生成してから、projectsテーブルに参加するだけです。

create table projects(project_id, forecast_value, start_date, end_date) as(
    select 001, 100, date '2017-01-01', date '2017-03-01' from dual union all 
    select 002, 200, date '2017-01-01', date '2017-05-01' from dual union all 
    select 003, 200, date '2017-10-01', date '2018-01-01' from dual 
); 


with 
    dates(dt) as(
     select add_months(s_date, level - 1) as dt 
     from (
      select min(start_date) as s_date 
       , max(end_date) as e_date 
       from projects 
      ) 
     connect by add_months(s_date , level - 1) <= e_date 
     ) 
select p.project_id 
    , p.forecast_value 
    , extract(year from d.dt) as forcast_year 
    , to_char(d.dt, 'MONTH') as forecast_month 
from projects p 
join dates d 
    on (trunc(d.dt, 'mm') between trunc(p.start_date, 'mm') 
          and trunc(p.end_date, 'mm')) 
order by p.project_id, d.dt 

結果:

PROJECT_ID FORECAST_VALUE FORCAST_YEAR FORECAST_MONTH 
---------- -------------- ------------ -------------- 
     1   100   2017 JANUARY  
     1   100   2017 FEBRUARY  
     1   100   2017 MARCH   
     2   200   2017 JANUARY  
     2   200   2017 FEBRUARY  
     2   200   2017 MARCH   
     2   200   2017 APRIL   
     2   200   2017 MAY   
     3   200   2017 OCTOBER  
     3   200   2017 NOVEMBER  
     3   200   2017 DECEMBER  
     3   200   2018 JANUARY  

12 rows selected. 
関連する問題