どの部分で苦労しているのか、なぜ多くのネストされたSQLを参照しているのかは少しわかりません。サンプルデータがなければ、私はいくつかを構成しなければなりませんでした:
create table t42 (my_date date, my_value number);
insert into t42 values (date '2006-01-31', 0601);
insert into t42 values (date '2006-12-31', 0612);
insert into t42 values (date '2007-01-31', 0701);
insert into t42 values (date '2007-12-31', 0712);
insert into t42 values (date '2008-01-31', 0801);
insert into t42 values (date '2008-12-31', 0812);
insert into t42 values (date '2009-01-31', 0901);
insert into t42 values (date '2009-12-31', 0912);
insert into t42 values (date '2010-01-31', 1001);
insert into t42 values (date '2010-12-31', 1012);
insert into t42 values (date '2011-01-31', 1101);
insert into t42 values (date '2011-12-31', 1112);
insert into t42 values (date '2012-01-31', 1201);
insert into t42 values (date '2012-02-29', 1202);
insert into t42 values (date '2012-03-31', 1203);
insert into t42 values (date '2012-04-30', 1204);
insert into t42 values (date '2012-05-31', 1205);
次に、内部クエリを使用して期間/年/月の「ラベル」を生成し、ダミーフィールドを使用して結果を並べ替え、さらに実際に関心のある値を生成できます。次に、外部クエリを使用してsum
、count
などを実行します。 。
select label, sum(my_value), count(1)
from
(
select
case when my_date < trunc(sysdate, 'YYYY') - interval '4' year then
'Before ' || to_char(trunc(sysdate, 'YYYY')
- interval '5' year, 'YYYY')
when my_date < trunc(sysdate, 'YYYY') - interval '1' year then
to_char(my_date, 'YYYY')
else to_char(my_date, 'Mon YYYY')
end as label,
case when my_date < trunc(sysdate, 'YYYY') - interval '4' year then
to_char(trunc(sysdate, 'YYYY') - interval '5' year, 'YYYYMM')
when my_date < trunc(sysdate, 'YYYY') - interval '1' year then
to_char(my_date, 'YYYY') || '01'
else to_char(my_date, 'YYYYMM')
end as order_field,
my_value
from t42
)
group by label, order_field
order by order_field;
私はtrunc(sysdate, 'YYYY')
今年の始まりを見つけるために使用し、次にinterval
5年前に戻るために使用し、それらの「バケット」に基づいてlabel
およびorder_field
疑似列を作成しています。このcase
ように使用すると、さまざまなバケットを使用できます。1つは、5年以上経過したものすべてに対応し、1つは昨年まで毎年、もう1つはそれ以降は毎月です。
LABEL SUM(MY_VALUE) COUNT(1)
----------------- ------------- ----------
Before 2007 2626 4
2008 1613 2
2009 1813 2
2010 2013 2
Jan 2011 1101 1
Dec 2011 1112 1
Jan 2012 1201 1
Feb 2012 1202 1
Mar 2012 1203 1
Apr 2012 1204 1
May 2012 1205 1
私は一度だけテーブルにアクセスしているので、パフォーマンスは、生データを操作する方法ではなく、生データを抽出する方法(結合と条件)に依存する必要があります。もちろんt42
、2つのテーブル間の現在の結合に置き換えて、関心のあるフィールドを引き出すことができます。
(+)
Oracleの外部結合の古い表記法ではなく、ANSI結合構文に切り替えることをお勧めします。また、これはデータがない年や月には対応していませんが、元のアウトラインにも対応していないため、問題にならない可能性があります。また、「Sum of year」の値をどのように生成するか、または少なくとも表示するかは、クライアントによって異なる場合があります。
ラベル生成をビューに分離して再利用可能にし、データのない期間を見つけられるようにします。
create or replace view v42 (period_label, period_order, period_start, period_end)
as
select 'Before ' || to_char(trunc(sysdate, 'YYYY') - interval '5' year, 'YYYY'),
'197001',
date '1970-01-01',
trunc(sysdate, 'YYYY') - interval '4' year - interval '1' second
from dual
union
select to_char(year_start, 'YYYY'),
to_char(year_start, 'YYYY') || '01',
year_start,
year_start + interval '1' year - interval '1' second
from (
select add_months(trunc(sysdate, 'YYYY'), - 12 * (level + 1)) as year_start
from dual connect by level <= 3
)
union
select to_char(month_start, 'Mon YYYY'),
to_char(month_start, 'YYYYMM'),
month_start,
month_start + interval '1' month - interval '1' second
from (
select add_months(trunc(sysdate, 'MM'), 1 - level) as month_start
from dual connect by level <= 12 + to_number(to_char(sysdate, 'MM'))
);
これは、元々持っていたラベルを作成するためのものです。すべての年を個別に表示する場合は、の最初の部分を削除し、月ごとに表示される年を変更するように句をunion
調整できます。connect by
(おそらくそれをパラメーター化することができますが、それはおそらく少し遠いです)。
「バケット」には3つのクラスがあり、1つのクラスは月ごと、1つは年ごとに分類され、それから過去のすべてのクラスがありました。ユニオンの各部分はそれらの1つに対応し、各クラス内のすべてのバケットの期間の開始日と終了日、およびラベルと後で注文するものを生成します。ビューを見て、おそらくそれぞれselect
を個別に見て、彼らが何をしているかを確認してください。
次に、そのビューを1つまたは複数のデータテーブルに結合します。一致するデータのないラベルを表示する場合は、左外側結合を使用します。
select v.period_label, nvl(sum(t.my_value), 0), count(t.my_value)
from v42 v
left join t42 t on t.my_date between v.period_start and v.period_end
group by v.period_label, v.period_order
order by v.period_order;
PERIOD_LABEL NVL(SUM(T.MY_VALUE),0) COUNT(T.MY_VALUE)
----------------- ---------------------- -----------------
Before 2007 2626 4
2008 1613 2
2009 1813 2
2010 2013 2
Jan 2011 1101 1
Feb 2011 0 0
...
Nov 2011 0 0
Dec 2011 1112 1
...