2

ほとんど連続した日を取り、それらが本当に連続しているかどうか、およびその日付に属する値に応じてグループ化するクエリを探しています。Oracle バージョン 11g を使用しています。

これはいくつかのサンプルデータです:

date          value
2012-01-01    2000
2012-01-02    2000 //(there is no data for Jan 03 for example)
2012-01-04    2000
2012-01-05    5000
2012-01-06    5000
2012-01-07    5000
2012-01-08    2000
2012-01-09    2000
2012-01-10    2000

(これは非常に大きなクエリの結果です)

私が探しているのは、これらの日を次のような期間にグループ化することです。

from_date   to_date     value
2012-01-01  2012-01-02  2000
2012-01-04  2012-01-04  2000
2012-01-05  2012-01-07  5000
2012-01-08  2012-01-10  2000

私たちは、私が望むことを行うクエリを作成することができましたが、それはあまり効率的な方法ではなく、より優れた/よりエレガントなものが存在すると確信しています. これは私が今使っているものです:

with temp_table as (
select a.pk_date DATE1, c.pk_date DATE2, a.volume VOL1
from dm_2203 a, dm_2203 c
where a.volume = c.volume
  and a.pk_date <= c.pk_date
  and not exists (select 1 from dm_2203 b
                  where a.volume = b.volume
                    and a.pk_date = b.pk_date+1)
  and not exists (select 1 from dm_2203 d
                  where c.volume = d.volume
                    and c.pk_date = d.pk_date-1)  )
select * from temp_table y
where date2-date1+1 = (select count(*)
                       from dm_2203 z
                       where z.pk_date between y.date1 and y.date2
                         and y.vol1 = z.volume)
order by 1;

誰もがこれをより速く、すべての結合なしで行う方法について考えを持っていますか? ありがとう!

4

2 に答える 2

3

私はこれを薄くしますこれはうまくいくはずであり、また合理的に効率的です(それは一度だけテーブルに当たるはずです)

create table t ( d date, v number);

insert into t values (trunc(sysdate), 100);
insert into t values (trunc(sysdate+2), 100);
insert into t values (trunc(sysdate+3), 100);
insert into t values (trunc(sysdate+4), 100);
insert into t values (trunc(sysdate+5), 200);
insert into t values (trunc(sysdate+6), 200);
insert into t values (trunc(sysdate+7), 200);
insert into t values (trunc(sysdate+8), 100);

select min(d), max(d), v
from (
    select d, v, 
        sum( gc) over (partition by v order by d) g
    from (
        select d, v, 
            (case (d - lag(d) over ( partition by v order by d) )
                when 1 then 0
                else 1
             end) gc
        from t
    )
) group by v, g
order by min(d), v

Note that if you want to run the logic in an efficient way on a subset of your data, you should add the where clause in the inner most select. Otherwise oracle will have problems to use any index.

于 2012-03-22T15:04:46.670 に答える
0

試す:

with cte as (
select pk_date from_date, pk_date to_date, volume
from dm_2203 d
where not exists
(select null from dm_2203 e 
 where d.volume = e.volume and d.pk_date-1 = e.pk_date)
union all
select c.pk_date from_date, d.pk_date to_date, c.volume
from cte c
join dm_2203 d on d.volume = c.volume and d.pk_date = c.pk_date+1)
select from_date, max(to_date) to_date, volume "value"
from cte
group by from_date, volume
于 2012-03-22T14:56:56.430 に答える