Oracle:获取所有月份的数据,如果没有数据则获取0

时间:2013-07-22 16:57:34

标签: oracle left-join

我有一个Mview,可以按idNumberMonth提供数据分组。所以如果没有特定月份的数据,我想显示0。这是我的问题:

select MonthName, myCost, myNumber 
  from
     (
       select MONTH mm, myCost, myNumber
         from myOracle_mv
     ) myTotals,
     (
       select to_char(date '2012-12-1' + numtoyminterval(level,'month'), 'mm') MonthName
        from dual
      connect by level <= 12
     ) ALLMONTHS
where mm = MonthName

所以我期待:

Month Number Data
-----------------------
1     abc123 4444
2     0
3     abc123 4444
4     abc123 4444
5     0
6     abc123 4444
7     abc123 4444
8     0
9     abc123 4444
10    abc123 4444
11    0
12    abc123 4444

相反,我仍然得到:

1    abc123  4444
3    abc123  4444
4    abc123  4444
6    abc123  4444
7    abc123  4444
9    abc123  4444
10   abc123  4444
12   abc123  4444

有什么想法吗?

谢谢!

编辑:谢谢你的回答。我确实在我的查询中有外部联接但忘记输入,因为集中于更改表/列的名称。

所以是的,我尝试过OUTER JOIN,但仍然没有得到预期的结果。非常感谢任何反馈。

编辑:这是myOracle_MV上的数据:

3777.24     AAA 1   2012
49973.12    AAA 2   2012
4049.91     AAA 3   2012
469.485     AAA 4   2012
5872.22     AAA 5   2012
65837.71    AAA 6   2012
566.23      AAA 7   2012
18432.95    AAA 8   2012
4337.75     AAA 12  2011
18811       BBB 1   2012
29872.67    BBB 2   2012
29068.55    BBB 3   2012
264957.8    BBB 4   2012
67673       BBB 5   2012
855.02      BBB 6   2012
5226.1      BBB 7   2012
2663.24     BBB 8   2012
5490.58     BBB 12  2011
3845.47     CCC 1   2012
3050.54     CCC 2   2012
3784.44     CCC 3   2012
799.73      CCC 4   2012
124884.2    CCC 5   2012
5157.24     CCC 6   2012
19184.78    CCC 7   2012
2280.05     CCC 8   2012
107.07      DDD 3   2012
181.78      DDD 4   2012
110.09      DDD 5   2012
18016.19    DDD 6   2012
1772.95     DDD 7   2012
63.32       DDD 8   2012

4 个答案:

答案 0 :(得分:5)

与现有答案非常相似,但是:

select months.month, mv.mycost, coalesce(mv.mynumber, 0) as mynumber
from (
  select to_char(date '1970-01-01'
    + numtoyminterval(level - 1, 'month'), 'mm') as month
  from dual
  connect by level <= 12) months
left join myoracle_mv mv
on mv.month = months.month
order by months.month, mv.mycost, mv.mynumber;

给出了您发布的数据:

MONTH MYCOST   MYNUMBER
----- ------ ----------
01    AAA       3777.24 
01    BBB         18811 
01    CCC       3845.47 
02    AAA      49973.12 
02    BBB      29872.67 
02    CCC       3050.54 
03    AAA       4049.91 
03    BBB      29068.55 
03    CCC       3784.44 
03    DDD        107.07 
04    AAA       469.485 
04    BBB      264957.8 
04    CCC        799.73 
04    DDD        181.78 
05    AAA       5872.22 
05    BBB         67673 
05    CCC      124884.2 
05    DDD        110.09 
06    AAA      65837.71 
06    BBB        855.02 
06    CCC       5157.24 
06    DDD      18016.19 
07    AAA        566.23 
07    BBB        5226.1 
07    CCC      19184.78 
07    DDD       1772.95 
08    AAA      18432.95 
08    BBB       2663.24 
08    CCC       2280.05 
08    DDD         63.32 
09                    0 
10                    0 
11                    0 
12    AAA       4337.75 
12    BBB       5490.58 

 35 rows selected

如果您想在mynumber列中显示零,那么您可以这样做:

select months.month, mv.mycost, coalesce(mv.mynumber, 0) as mynumber

给出:

...
08    DDD         63.32 
09                    0 
10                    0 
11                    0 
12    AAA       4337.75 
...

根据对Jafar回答的评论,听起来好像你自己已经走得那么远,但是对于所有月份的所有mycost值,你想要零值。如果是这种情况,那么您需要获取mycost和外部联接的可能值列表。这将获取MV中的所有值:

select months.month, costs.mycost, coalesce(mv.mynumber, 0) as mynumber
from (
  select to_char(date '1970-01-01'
    + numtoyminterval(level - 1, 'month'), 'mm') as month
  from dual
  connect by level <= 12) months
cross join (
  select distinct mycost
  from myoracle_mv) costs
left join myoracle_mv mv
on mv.month = months.month
and mv.mycost = costs.mycost
order by months.month, costs.mycost, mv.mynumber;

并给出:

MONTH MYCOST   MYNUMBER
----- ------ ----------
01    AAA       3777.24 
01    BBB         18811 
01    CCC       3845.47 
01    DDD             0 
02    AAA      49973.12 
02    BBB      29872.67 
02    CCC       3050.54 
02    DDD             0 
03    AAA       4049.91 
03    BBB      29068.55 
03    CCC       3784.44 
03    DDD        107.07 
04    AAA       469.485 
04    BBB      264957.8 
04    CCC        799.73 
04    DDD        181.78 
05    AAA       5872.22 
05    BBB         67673 
05    CCC      124884.2 
05    DDD        110.09 
06    AAA      65837.71 
06    BBB        855.02 
06    CCC       5157.24 
06    DDD      18016.19 
07    AAA        566.23 
07    BBB        5226.1 
07    CCC      19184.78 
07    DDD       1772.95 
08    AAA      18432.95 
08    BBB       2663.24 
08    CCC       2280.05 
08    DDD         63.32 
09    AAA             0 
09    BBB             0 
09    CCC             0 
09    DDD             0 
10    AAA             0 
10    BBB             0 
10    CCC             0 
10    DDD             0 
11    AAA             0 
11    BBB             0 
11    CCC             0 
11    DDD             0 
12    AAA       4337.75 
12    BBB       5490.58 
12    CCC             0 
12    DDD             0 

 48 rows selected 

但希望你有另一个表格,其中包含可能的mycost值(假设代表某个成本中心,而不是价格;稍微难以分辨什么),你可以使用它而不是子查询

SQL Fiddle

另请注意,如果您想添加过滤条件,例如要将数据限制到特定年份,您需要在left join子句中执行此操作,而不是作为where子句,或者将外部联接还原为内部联接。例如,adding this

where mv.year = 2011

意味着你只能回到两行:

MONTH MYCOST   MYNUMBER
----- ------ ----------
12    AAA       4337.75 
12    BBB       5490.58 

但是如果你made than another condition on the outer join,你仍然可以获得48行,其中46行有零,两行有上述值:

...
left join myoracle_mv mv
on mv.month = months.month
and mv.mycost = costs.mycost
and mv.year = 2011
order by months.month, costs.mycost, mv.mynumber;

...
11    CCC             0 
11    DDD             0 
12    AAA       4337.75 
12    BBB       5490.58 
12    CCC             0 
12    DDD             0 

 48 rows selected 

答案 1 :(得分:2)

您需要在两个内联视图之间进行外部联接

select MonthName, myCost, myNumber 
  from (select MONTH mm, myCost, myNumber
          from myOracle_mv
       ) myTotals
       right outer join
       (select to_char(date '2012-12-1' + numtoyminterval(level,'month'), 'mm') MonthName
          from dual
       connect by level <= 12) ALLMONTHS
       on( myTotals.mm = allmonths.MonthName )

您也可以使用旧的Oracle特定(+)语法进行外连接,但我通常建议使用SQL标准语法。

答案 2 :(得分:2)

也许是这样的

select MonthName, COALESCE(myCost,0), myNumber 
  from
     (
       select to_char(date '2012-12-1' + numtoyminterval(level,'month'), 'mm') MonthName
        from dual
      connect by level <= 12
     ) ALLMONTHS LEFT OUTER JOIN
     (
       select MONTH mm, myCost, myNumber
         from myOracle_mv
     ) myTotals ON 
    mm = MonthName

答案 3 :(得分:1)

您需要在查询结尾处进行外部联接((+)):

select MonthName, myCost, myNumber from
(
select
MONTH mm, myCost, myNumber
from
myOracle_mv
) myTotals,
(
select
to_char(date '2012-12-1' + numtoyminterval(level,'month'), 'mm') MonthName
from
dual
connect by level <= 12
)ALLMONTHS
where mm = MonthName(+)

对于您的示例,您不需要计算日期:

 select MONTH mm, NVL(myCost, 0), myNumber
 from
    (select level from dual connect by level <= 12) NUM
    left outer join  myOracle_mv MV  ON ( MV.MONTH  = NUM.level )
;