sql >> Database >  >> RDS >> Oracle

Oracle:krijg gegevens over alle maanden, 0 als er geen gegevens zijn

Zeer vergelijkbaar met bestaande antwoorden, maar dit:

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;

geeft dit met de gegevens die je hebt gepost:

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

Als u een nul wilt laten verschijnen in het mynumber kolom dan kun je dat maken:

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

wat geeft:

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

Uit de opmerkingen over Jafar's antwoord klinkt het alsof je misschien zo ver bent gekomen in je eentje, maar je wilt nulwaarden voor alle mycost waarden voor alle maanden. Als dat het geval is, moet u de lijst met mogelijke waarden voor mycost . opvragen en de buitenste sluit zich daar ook bij aan. Dit neemt alle waarden die al in de MV staan:

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;

en geeft:

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 

Maar hopelijk heb je een andere tabel met de mogelijke mycost waarden (ervan uitgaande dat dit zoiets als een kostenplaats voorstelt, in plaats van een prijs; enigszins moeilijk te zeggen wat wat is) en u kunt dat gebruiken in plaats van de subquery.

SQL Fiddle .

Houd er ook rekening mee dat als u een filter wilt toevoegen, b.v. om gegevens te beperken tot een bepaald jaar, moet u dat doen in de left join clausule, niet als een where clausule, of je zou de outer join terugzetten naar een inner. Bijvoorbeeld, dit toevoegen :

where mv.year = 2011

zou betekenen dat je maar twee rijen terug hebt:

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

Maar als je maakte dan een andere voorwaarde op de outer join je zou nog steeds 48 rijen terugkrijgen, waarvan 46 met nullen en twee met de bovenstaande waarden:

...
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. MySQL-weergaven - Wanneer wel en niet gebruiken?

  2. Verbinding maken met MySQL met behulp van Groovy

  3. Wat is het verschil tussen pls_integer en binary_integer?

  4. Ondersteunt MySQL controlebeperkingen?