[英]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.