2015-09-14 42 views
0

这是关系到Mysql to select month-wise record even if data not existHow to fill in missing months?,但对于Oracle和额外数据。我想用一个水晶报表交叉表,但需要对数据零点为了得到列数月(见Keeping same number of columns at cross tab report如何填补缺失月份的数据在Oracle查询

我的查询返回的数据,如

NewRate OldRate Month Count 
    Rate1  Rate2  8  1 
    Rate1  Rate3  2  3 
    Rate1  Rate3  3  2 
    Rate1  Rate3  7  2 
    Rate1  Rate3  8  12 
    Rate3  Rate1  1  1 
    Rate3  Rate1  2  1 
    Rate3  Rate1  5  1 
    Rate3  Rate1  7  3 
    Rate3  Rate1  8  9 

我想为交叉表每个NewRate,但为了获得每个月的列,我需要返回额外的行,并为每个NewRate值和所有月份记录一次。所以,我需要一个查询来获取我下面的附加记录(含OldRate是只是每个NewRate选项之一)

NewRate OldRate Month Count 
    Rate1  Rate2  1  0 
    Rate1  Rate2  2  0 
    Rate1  Rate2  3  0 
    Rate1  Rate2  4  0 
    Rate1  Rate2  5  0 
    Rate1  Rate2  6  0 
    Rate1  Rate2  7  0 
    Rate1  Rate2  9  0 
    Rate1  Rate2 10  0 
    Rate1  Rate2 11  0 
    Rate1  Rate2 12  0 
    Rate3  Rate1  3  0 
    Rate3  Rate1  4  0 
    Rate3  Rate1  6  0 
    Rate3  Rate1  9  0 
    Rate3  Rate1 10  0 
    Rate3  Rate1 11  0 
    Rate3  Rate1 12  0 

我目前的查询有特定的日期,而不仅仅是数月,这可能工作更好一点。我愿意使用1-1-2015,2-1-2015等日期,如果已经有了1月5日,那么在1月1日加上0计数不会造成伤害。

但是,我不想为不存在的费率分组添加记录。 Rate1到Rate2和Rate1到Rate3都是零的,都是零。但由于原始数据集没有Rate3到Rate2,我不想添加这些数据。费率是Oracle过程的参数,日期范围(也是参数)默认为当前日历年。

回答

2

您正在期待致密您的数据,并有许多帖子和答案如何做到这一点。本质上,您需要生成一组所有可能的行,然后将外部实际数据添加到理论集。

在这个例子中,我使用CONNECT BY子句生成一组个月。你提到你的实际数据集使用实际日期,所以我在这个例子中使用了日期类型。

select to_date(level, 'MM') mo 
from dual 
connect by level <=12 

我物化在WITH条款的日期(连同您的样本数据),但你可以做同样的内嵌视图中。

然后在主查询,你可以把这些密集的日期和十字一套独特率的组合来创建一组的实际速率集和日期,所有可能的组合中加入他们的行列。为此,我们然后LEFT OUTER JOIN您的实际数据,填写缺失计数与您的默认0

with 
-- Your sample data 
sample_data as ( 
    select 'Rate1' NewRate, 'Rate2' OldRate, to_date(8, 'MM') Month, 1 Count from dual union all 
    select 'Rate1', 'Rate3', to_date(2, 'MM'), 3 from dual union all 
    select 'Rate1', 'Rate3', to_date(3, 'MM'), 2 from dual union all 
    select 'Rate1', 'Rate3', to_date(7, 'MM'), 2 from dual union all 
    select 'Rate1', 'Rate3', to_date(8, 'MM'), 12 from dual union all 
    select 'Rate3', 'Rate1', to_date(1, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(2, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(5, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(7, 'MM'), 3 from dual union all 
    select 'Rate3', 'Rate1', to_date(8, 'MM'), 9 from dual), 

-- Using the "with clause" we can generate a set of months as rows 
dense_months as (
    select to_date(level, 'MM') mo 
    from dual 
    connect by level <=12) 

select 
    rg.newrate, rg.oldrate, dm.mo, nvl(sd.count,0) count 
-- Here we are creating a cartesian product of your rate groups and twelve calendar months 
from dense_months dm 
cross join 
    (select distinct newrate, oldrate 
    from sample_data) rg 
-- Then we can left join our actual data to the cartesian product. 
left outer join sample_data sd on rg.newrate = sd.newrate and rg.oldrate = sd.oldrate and dm.mo = sd.month 
order by 1, 2, 3; 

这里是一个SQL Fiddle工作示例。

+0

我只是想调出并批准建议的'分区外连接',每@诺埃尔的答案在下面。这是一个很大的简化,坦率地说,当我写我的回复时(我可能很匆忙),我的思想开始滑落。 – Wolf

3

您可以使用partitioned outer join这一点,这将消除交叉连接。

感谢@Wolf为SQL Fiddle

查询1

with 
-- Your sample data 
sample_data as ( 
    select 'Rate1' NewRate, 'Rate2' OldRate, to_date(8, 'MM') Month, 1 Count from dual union all 
    select 'Rate1', 'Rate3', to_date(2, 'MM'), 3 from dual union all 
    select 'Rate1', 'Rate3', to_date(3, 'MM'), 2 from dual union all 
    select 'Rate1', 'Rate3', to_date(7, 'MM'), 2 from dual union all 
    select 'Rate1', 'Rate3', to_date(8, 'MM'), 12 from dual union all 
    select 'Rate3', 'Rate1', to_date(1, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(2, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(5, 'MM'), 1 from dual union all 
    select 'Rate3', 'Rate1', to_date(7, 'MM'), 3 from dual union all 
    select 'Rate3', 'Rate1', to_date(8, 'MM'), 9 from dual), 

-- Using the "with clause" we can generate a set of months as rows 
dense_months as (
    select to_date(level, 'MM') mo 
    from dual 
    connect by level <=12) 

select 
    sd.newrate, sd.oldrate, dm.mo, nvl(sd.count,0) count 
from sample_data sd 
partition by (sd.newrate, sd.oldrate) 
right outer join dense_months dm 
on dm.mo = sd.month 
order by 1, 2, 3 

Results

| NEWRATE | OLDRATE |       MO | COUNT | 
|---------|---------|-----------------------------|-------| 
| Rate1 | Rate2 | January, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 | February, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 |  March, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 |  April, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 |  May, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 |  June, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 |  July, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 | August, 01 2015 00:00:00 |  1 | 
| Rate1 | Rate2 | September, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 | October, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 | November, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate2 | December, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 | January, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 | February, 01 2015 00:00:00 |  3 | 
| Rate1 | Rate3 |  March, 01 2015 00:00:00 |  2 | 
| Rate1 | Rate3 |  April, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 |  May, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 |  June, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 |  July, 01 2015 00:00:00 |  2 | 
| Rate1 | Rate3 | August, 01 2015 00:00:00 | 12 | 
| Rate1 | Rate3 | September, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 | October, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 | November, 01 2015 00:00:00 |  0 | 
| Rate1 | Rate3 | December, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 | January, 01 2015 00:00:00 |  1 | 
| Rate3 | Rate1 | February, 01 2015 00:00:00 |  1 | 
| Rate3 | Rate1 |  March, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 |  April, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 |  May, 01 2015 00:00:00 |  1 | 
| Rate3 | Rate1 |  June, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 |  July, 01 2015 00:00:00 |  3 | 
| Rate3 | Rate1 | August, 01 2015 00:00:00 |  9 | 
| Rate3 | Rate1 | September, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 | October, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 | November, 01 2015 00:00:00 |  0 | 
| Rate3 | Rate1 | December, 01 2015 00:00:00 |  0 |