2010-11-12 3 views
5

Ho una tabella "prezzi" con colonne:vista Tricky per Oracle

year, janprc, janqty, febprc, febqty ... 

(prezzi e quantyties per tutti i mesi in un anno)

cosa ho bisogno è di creare una vista "monthlyprices "con le colonne:

year, month, price, quantity 

utilizzando i dati della tabella sopra. come potrei farlo?

Grazie!

+9

Prima applicare un giornale arrotolato alla persona che "disegnato" quel tavolo ... –

+5

@Tony: Basta essere contento che non hanno fatto '2010janprc, 2010janqty ... 2011janprc , 2011janqty ... '. :) –

+2

qualcuno ha 11g di calci che possono dare un'occhiata a 'unpivot'? – ninesided

risposta

1

è più o meno semplice come scrivere 12 sub-query e UNION ing loro risultati insieme:

CREATE VIEW MONTHLYPRICES AS 

SELECT 
    year  AS year, 
    'January' AS month, 
    janprc  AS price, 
    janqty  AS quantity 
FROM 
    PRICES 

UNION ALL 

SELECT 
    year  AS year, 
    'February' AS month, 
    febprc  AS price, 
    febqty  AS quantity 
FROM 
    PRICES 

UNION ALL 

SELECT 
    year  AS year, 
    'March' AS month, 
    marprc  AS price, 
    marqty  AS quantity 
FROM 
    PRICES 

UNION ALL 

    ... and so on ... 

È possibile utilizzare UNION ALL perché sai che non ci sarà alcun duplicati.

1

Usa 11 sindacati per costruire la tabella da un mese alla volta,

with t as (
    select 2008 year, 1 janprc, 1 janqty, 1 febprc, 1 febqty from dual 
    union 
    select 2009,  50,  10,  20,  30  from dual 
    union 
    select 2010,  60,  10,  25,  30  from dual 
) 
select year, 'jan' month, janprc price, janqty quantity from t 
union 
select year, 'feb',  febprc,  febqty   from t 
; 

alt text

Ciò presuppone non v'è più di un record per anno. Se esiste più di un record all'anno, utilizzare UNION ALL per conservare le righe duplicate.

1

Potreste essere in grado di utilizzare l'operazione di Oracle 11g UNPIVOT, non ho un'istanza di 11g che si spaventa in giro per provare contro, anche se ho paura.

+0

A meno che non mi sbagli, 'UNPIVOT' può solo produrre una colonna (non due), corretta? Come potrebbe essere in grado di fornire il prezzo ** e la quantità ** tramite 'UNPIVOT'? –

0

Se UNPIVOT è disponibile, è consigliabile utilizzarlo. Per le versioni precedenti di Oracle è possibile incrociare unirsi alla tabella con una tabella dei nomi dei mesi (generati o pre-compilati) e quindi utilizzare le istruzioni decodifica o caso per selezionare il mese, il prezzo e la quantità corretti. Ecco come sarebbe questo.

create table prices (Year Varchar2(4), JanPrc Number(3), JanQty Number(3), 
    FebPrc Number(5,2), FebQty Number(3), MarPrc Number(3), MarQty Number(3)); 
insert into prices values ('2008',1,500,1,600,1,700); 
insert into prices values ('2009',50,100,20,300,30,800); 
insert into prices values ('2010',60,5,70,10,80,15); 

SELECT Year, Month, DECODE(MonthNumber,1,JanPrc,2,FebPrc,MarPrc) Price, 
    DECODE(MonthNumber,1,JanQty,2,FebQty,MarQty) Quantity 
FROM Prices 
    CROSS JOIN (
    SELECT rownum MonthNumber, 
      to_char(to_date(to_char(rownum,'FM00') || '2000','MMYYYY'), 
       'FMMonth') Month 
     FROM dual CONNECT BY rownum <= 3 
) 
ORDER BY Year, MonthNumber; 
1

L'approccio sindacale mi sembra un po 'doloroso. Puoi farlo in questo modo, sostituendo il nome della tua tabella reale per so_4164416 e scegliendo il modo in cui vuoi rappresentare i mesi - forse non i nomi completi (e ho il sospetto che ci sia un modo migliore per generare comunque i nomi dei mesi!):

create or replace view monthlyprices as 
with tmp_month_num as 
    (select rownum as month_num from dual connect by level <= 12) 
select so.year, 
    trim(to_char(to_date('01/' || tmn.month_num || '/2010','DD/MM/YYYY'), 
     'Month')) month, 
    case tmn.month_num 
     when 01 then so.janprc 
     when 02 then so.febprc 
     when 03 then so.marprc 
     when 04 then so.aprprc 
     when 05 then so.mayprc 
     when 06 then so.junprc 
     when 07 then so.julprc 
     when 08 then so.augprc 
     when 09 then so.sepprc 
     when 10 then so.octprc 
     when 11 then so.novprc 
     when 12 then so.decprc end as price, 
    case tmn.month_num 
     when 01 then so.janqty 
     when 02 then so.febqty 
     when 03 then so.marqty 
     when 04 then so.aprqty 
     when 05 then so.mayqty 
     when 06 then so.junqty 
     when 07 then so.julqty 
     when 08 then so.augqty 
     when 09 then so.sepqty 
     when 10 then so.octqty 
     when 11 then so.novqty 
     when 12 then so.decqty end as quantity 
from so_4164416 so, tmp_month_num tmn 
order by so.year, tmn.month_num; 

select * from monthlyprices where year = 2009 and month = 'January'; 
+0

Suppongo che "doloroso" sia soggettivo. Nella mia opinione (molto soggettiva), * questo * sembra più doloroso di 'UNION'. :) –

+0

Quindi 'a me' . Generalmente penserei che il sindacato sarebbe più difficile da mantenere, anche se probabilmente non è un problema qui. E anche soggettivo, ovviamente. –

+0

non è la manutenzione di cui mi preoccuperei, ma le prestazioni. Direi che la soluzione di Alex è più performante di quella uber-union, ma suppongo che dipenda dai dati. – ninesided

9

Ecco come farlo con una dichiarazione UNPIVOT e senza UNION.

with t as (
    select 2008 year, 1 janprc, 500 janqty, 1 febprc, 600 febqty from dual 
    union 
    select 2009,  50,  1000,  20,  3000  from dual 
    union 
    select 2010,  60,  1000,  25,  3000  from dual 
) 
SELECT * 
FROM t 
UNPIVOT (
    (price, quantity) FOR month IN 
    (
    (janprc, janqty) AS 'jan', 
    (febprc, febqty) AS 'feb' 
) 
) 
order by 
    year, month 
; 

alt text

+0

+1: assolutamente fantastico! –

+2

Puntate su @nineided per avermi ispirato a combattere con i diagrammi di sintassi UNPIVOT che tormentano la mente. Ne è valsa la pena. –

+0

@Janek: dov'è il diagramma di sintassi? Lo stavo cercando ... –