Хитрый взгляд на Oracle - PullRequest
       20

Хитрый взгляд на Oracle

5 голосов
/ 12 ноября 2010

У меня есть таблица "цены" с колонками:

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

(цены и количество за все месяцы года)

мне нужно создать представление "ежемесячные цены" со столбцами:

year, month, price, quantity 

с использованием данных из таблицы выше. как я могу это сделать?

Спасибо!

Ответы [ 6 ]

9 голосов
/ 12 ноября 2010

Вот как это сделать с одним оператором UNPIVOT и без 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

1 голос
/ 12 ноября 2010

Профсоюзный подход мне кажется немного болезненным. Вы можете сделать это следующим образом, заменив реальное имя таблицы на 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';
1 голос
/ 12 ноября 2010

Возможно, вы сможете использовать операцию Oracle 11g UNPIVOT , у меня нет экземпляра 11g, который можно протестировать, хотя я боюсь.

1 голос
/ 12 ноября 2010

Используйте 11 СОЮЗОВ, чтобы составить таблицу, которую вы хотите один месяц за один раз,

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 для сохранения повторяющихся строк.

1 голос
/ 12 ноября 2010

Это почти так же просто, как написать 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, потому что знаете, что дубликатов не будет.

0 голосов
/ 12 ноября 2010

Если доступно UNPIVOT, вы обязательно должны его использовать.Для более ранних версий Oracle вы можете перекрестно объединить свою таблицу с таблицей названий месяцев (сгенерированных или предварительно созданных), а затем использовать операторы декодирования или регистр для выбора правильного месяца, цены и количества.Вот как это будет выглядеть.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...