2017-11-10 10 views
0

例!私は4列のテーブルを持っています。この場合、日付フォーマットDD.MM.YY交差していない期間の最小/最大日付の選択

id ban start  end 
1 1  01.01.15 31.12.18 
1 1  02.02.15 31.12.18 
1 1  05.04.15 31.12.17 

行2及び3からの日付は5行目から日付が行から日付に含まれている。この場合、列から日付1

1 1  02.04.19 31.12.20 
1 1  05.05.19 31.12.20 

に含まれています4.基本的に、交差していない2つの期間があります。日付が別で1つの期間で始まり、終わる

01.01.15 31.12.18 

02.04.19 31.12.20 

状況は不可能です。最終結果は

私はanalitical機能(LAG)を使用してみました。この

1 1  01.01.15 31.12.18 
1 1  02.04.19 31.12.20 

のように、私は行を注文すると、現在の日付が以前に含まれている場合、私はそれらを交換

select id 
    , ban 
    , case 
    when start >= nvl(lag(start) over (partition by id, ban order by start, end asc), start) 
    and end <= nvl(lag(end) over (partition by id, ban order by start, end asc), end) 
    then nvl(lag(start) over (partition by id, ban order by start, end asc), start) 
    else start 
    end as start 
    , case 
    when start >= nvl(lag(start) over (partition by id, ban order by start, end asc), start) 
    and end <= nvl(lag(end) over (partition by id, ban order by start, end asc), end) 
    then nvl(lag(end) over (partition by id, ban order by start, end asc), end) 
    else end 
    end as end 
from table 

になります。私はちょうど2行を持っている場合、それは動作します。たとえば、この

1 1 08.09.15 31.12.99 
1 1 31.12.15 31.12.99 

は、私はその後、すべてのフィールドでグループは、私が欲しいものを得ることができ、この

1 1 08.09.15 31.12.99 
1 1 08.09.15 31.12.99 

になり、より多く存在する場合

1 2  13.11.15 31.12.99 
1 2  31.12.15 31.12.99 
1 2  16.06.15 31.12.99 

私は

を取得します
1 2  16.06.15 31.12.99 
1 2  16.06.15 31.12.99 
1 2  13.11.15 31.12.99 

私はこれがなぜ起こるのか理解していますnsですが、どうすれば回避できますか?クエリを複数回実行することはオプションではありません。

+0

どのOracleのバージョン。 12の場合は、match_recognizeが答えになります。http://modern-sql.com/feature/match_recognize –

+1

"日付形式dd.MM.yy" - 日付形式はありません。それらは[7-bytes](https://stackoverflow.com/questions/13568193/how-are-dates-stored-in-oracle)として内部的に保存され、デフォルトでフォーマットするユーザーインターフェイスです(通常は'NLS_DATE_FORMAT'セッションパラメータ)を使用します。 – MT0

+0

@ MT0私の間違い。私はオラクルにあまりよく慣れていない。しかし、情報ありがとう) – Evgenii

答えて

1

-- test data 
with t(id, ban, dtstart, dtend) as (
    select 1, 1, date '2015-01-01', date '2015-03-31' from dual union all 
    select 1, 1, date '2015-02-02', date '2015-03-31' from dual union all 
    select 1, 1, date '2015-03-15', date '2015-03-31' from dual union all 
    select 1, 1, date '2015-08-05', date '2015-12-31' from dual union all 
    select 1, 2, date '2015-01-01', date '2016-12-31' from dual union all 
    select 2, 1, date '2016-01-01', date '2017-12-31' from dual), 
-- end of test data 
step1 as (select id, ban, dt, to_number(inout) direction 
      from t unpivot (dt for inout in (dtstart as '1', dtend as '-1'))), 
step2 as (select distinct id, ban, dt, direction, 
       sum(direction) over (partition by id, ban order by dt) sm 
      from step1), 
step3 as (select id, ban, direction, dt dt1, 
       lead(dt) over (partition by id, ban order by dt) dt2 
      from step2  
      where (direction = 1 and sm = 1) or (direction = -1 and sm = 0)) 
select id, ban, dt1, dt2 
    from step3 where direction = 1 order by id, ban, dt1 
  • step1 - 終了日をピックアップし、開始日に1-1終了を指定 日付(コラムdirection
  • STEP2 - direction
  • STEP3の累積合計を追加 - フィルタだけ面白い日付、lead()

を使用してピボット二日あなたはこの構文を短縮することができ、私は何が起こっているかを示すためにステップにそれを分割しました。

結果:

ID  BAN DT1   DT2 
------ ---------- ----------- ----------- 
    1   1 2015-01-01 2015-03-31 
    1   1 2015-08-05 2015-12-31 
    1   2 2015-01-01 2016-12-31 
    2   1 2016-01-01 2017-12-31 

が、私は違う(ID、BAN)のために、我々は個別に計算をしなければならないと仮定しました。そうでない場合は、sum()lead()でパーティション分割と並べ替えを変更します。

Pivotunpivot Oracleの11作品以降、以前のバージョンのためにあなたがcase whenを必要としています。

BTW - STARTはOracleの予約語なので、私の例ではわずかに列名を変更しました。

0

私は、グループを定義するには、累積合計をやって、期間が開始を識別することによって、これを行うのが好き、そして最終集計:このクエリは有望に見える

select id, ban, min(start), max(end) 
from (select t.*, sum(start_flag) over (partition by id, bin order by start) as grp 
     from (select t.*, 
        (case when exists (select 1 
             from t t2 
             where t2.id = t.id and t2.ban = t.ban and 
              t.start <= t2.end and t.end >= t2.start and 
              t.start <> t2.start and t.end <> t2.end 
            ) 
         then 0 else 1 
        end) as start_flag 
      from t 
      ) t 
    ) t 
group by id, ban, grp; 
+0

'存在する場合は'いつも0を返しますか?ここで 't.start <= t2.endとt.end> = t2.start'、行がそれ自身と比較されるたびに、開始は明らかに終了の前と終了の後で終わります。 @Evgenii。 – Evgenii

+0

。 。 。良いキャッチ。クエリを修正しました。 –

関連する問題