这与Mysql to select month-wise record even if data not exist和How to fill in missing months?有关,但对于Oracle和其他数据。我想使用Crystal Reports交叉表,但需要零数据才能获得这几个月的列(参见Keeping same number of columns at cross tab report)
我的查询返回
等数据 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日,那么添加一个带0计数的Jan 1将不会受到影响。
但是,我不想为不存在的Rate分组添加记录。将Rate1改为Rate2和Rate1改为Rate3将全部为零。但由于原始数据集没有Rate3到Rate2,我不想添加它们。费率是Oracle程序的参数,日期范围(也是参数)默认为当前日历年。
答案 0 :(得分: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 |
答案 1 :(得分:2)
您希望 densify 您的数据,并且有很多关于如何执行此操作的帖子和答案。基本上你需要生成一组所有可能的行,然后将你的实际数据左外连接到理论集。
在此示例中,我使用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工作示例。