繁体   English   中英

如何在Oracle查询中填写缺少的月份数据

[英]How to fill in missing month data in an Oracle query

这与Mysql有关, 即使数据不存在也可以选择按月记录,以及如何填写缺少的月份? ,但适用于Oracle和其他数据。 我想使用Crystal Reports交叉表,但需要零数据才能获取月份的列(请参阅在交叉表报表中保持相同的列数

我的查询返回的数据如

  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且计数为0不会影响1月1日。

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

您可以为此使用分区外部联接 ,这将消除交叉联接。

感谢@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

结果

| 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 |

您正在寻找使数据更致密的方法,有关此操作的文章和答案很多。 本质上,您需要生成一组所有可能的行,然后将外部实际数据与理论集进行外部连接。

在此示例中,我使用CONNECT BY子句来生成一组月份。 您提到您的实际数据集使用实际日期,因此在此示例中我使用的是日期类型。

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

我正在WITH子句中(与您的示例数据一起)实现这些日期,但是您也可以在嵌入式视图中执行相同的操作。

然后,在主查询中,您可以获取那些密集的日期,并将它们与唯一的比率组合集交叉连接,以创建一组实际比率组和日期的所有可能组合。 为此,我们然后将LEFT OUTER JOIN数据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工作示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM