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