我有点不清楚您在处理哪个部分,或者您为什么要引用许多嵌套 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 追溯五年,并根据这些“桶”生成label 和order_field 伪列.像这样使用 case 可以让我拥有不同的存储桶 - 一个用于超过 5 年的所有东西,一个用于直到去年的每一年,一个用于此后的每个月。
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 替换为两个表之间的当前连接,然后提取您感兴趣的字段。
我建议您切换到 ANSI 连接语法,而不是 Oracle 用于外部连接的旧 (+) 表示法。这不涉及任何没有任何数据的年份或月份,但您的原始大纲也没有,所以这可能不是问题。您如何生成或至少显示“年度总和”值可能取决于您的客户。
将标签生成分离到一个视图中,使其可重用并允许您找到没有数据的时段:
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 子句以更改按月显示的年份。 (您可以对其进行参数化,但这可能有点远)。
你有三类“桶”,一类是按月分类,一类是按年分类,然后是对过去太远的东西的统称;联合的每个部分都针对其中一个部分,为每个类中的所有存储桶生成周期开始和结束日期,加上标签和稍后订购的东西。查看视图,也许每个 select 单独查看,看看他们在做什么。
然后将该视图加入您的数据表或表;如果您想显示没有匹配数据的标签,请使用左外连接:
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
...