对Oracle的棘手观点

时间:2010-11-12 12:06:21

标签: sql oracle view union

我有一个表“价格”列:

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

(一年中所有月份的价格和数量)

我需要的是创建一个包含以下列的视图“monthlyprices”:

year, month, price, quantity 

使用上表中的数据。 我怎么能这样做?

谢谢!

6 个答案:

答案 0 :(得分:9)

以下是如何使用一个UNPIVOT语句而不是UNIONs。

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

答案 1 :(得分:1)

这就像编写12个子查询和UNION他们的结果一样简单:

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 ...

您可以使用UNION ALL,因为您知道不会有任何重复。

答案 2 :(得分:1)

使用11个UNION一次构建一个月的表,

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

这假设每年不超过一条记录。如果每年有多个记录,请使用UNION ALL保留重复的行。

答案 3 :(得分:1)

您可以使用Oracle 11g的UNPIVOT操作,虽然我害怕,但我没有使用11g实例进行测试。

答案 4 :(得分:1)

工会方法对我来说有点痛苦。您可以这样做,替换您的真实表名so_4164416并选择您想要表示月份的方式 - 也许不是全名(我怀疑有更好的方法来生成月份名称!):

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';

答案 5 :(得分:0)

如果UNPIVOT可用,您绝对应该使用它。对于早期版本的Oracle,您可以将表与月份名称表(生成或预构建)交叉连接,然后使用decode或case语句选择正确的月份,价格和数量。这是看起来的样子。

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;