До версии 11 задача транспонирования решалась довольно сложно.
В версии 11 в синтаксисе оператора SELECTпоявились фразы PIVOT и UNPIVOT , которые выполняют такое транспонирование прозрачно и просто.
План запроса получается простой и эффективный -- запрос будет хорошо выполняться даже на больших объёмах. Прежние варианты с самосоединением таблиц были бы менее эффективны
Приведу пример использования:
Имеем таблицу курсов валют к рублю:
ISO_CODE | RATE_DATE | RATE_VALUE | |||||
EUR | 01.02.2012 | 39,9678 | |||||
EUR | 02.02.2012 | 39,6777 | |||||
EUR | 03.02.2012 | 39,7664 | |||||
UAH | 01.02.2012 | 3,7731 | |||||
UAH | 02.02.2012 | 3,7881 | |||||
UAH | 03.02.2012 | 3,7547 | |||||
USD | 01.02.2012 | 30,3131 | |||||
USD | 02.02.2012 | 30,4067 | |||||
USD | 03.02.2012 | 30,1855 |
Хотим получить такую таблицу
RATE_DATE | RATE_EUR | RATE_UAH | RATE_USD |
01.02.2012 | 39,9678 | 3,7731 | 30,3131 |
02.02.2012 | 39,6777 | 3,7881 | 30,4067 |
03.02.2012 | 39,7664 | 3,7547 | 30,1855 |
В 11g это можно сделать таким запросом:
select * from (select ISO_CODE, RATE_DATE, RATE_VALUE from EXCH_RATES)
pivot (max (RATE_VALUE)for ISO_CODE in ('EUR' as RATE_EUR, 'UAH' as RATE_UAH, 'USD' as RATE_USD)
)
Искать pivot_clause
Как транспонировать несколько полей ?
В приведённом выше примере мы транспонировали только одно поле -- RATE_VALUE превратилось в RATE_EUR, RATE_UAH, RATE_USD
Но бывают задачи, когда нужно транспонировать несколько полей, ниже я привожу пример, связанный тоже с курсами валют, но курсы взяты с рынка Форекс, и там строка курса содержит несколько значений OPEN (значение на момент начала интервала), MIN (минимальное, которое достигалось в интервале), MAX (максимальное, которое достигалось в интервале), CLOSE (каким значением курса интервал закончился), VOLUME (объём операций)
В этом случае, названия колонок нам нужно собрать перемножением множества значений ('OPEN', 'MIN', 'MAX', 'CLOSE', 'VOLUME') на множество значений названий пар валют
Этот запрос можно написать так, что в каждой колонке сначала будет название пары валют (поле из FOR) и через подчёркивание название поля, которое мы транспонируем
Сначала приведу запрос
select * from (select * from RATES)
pivot (avg (QOPEN) as QOPEN,
avg (QMIN) as QMIN,
avg (QMAX) as QMAX,
avg (QCLOSE) as QCLOSE,
avg (QVOLUME) as QVOLUME
for (CURPAIR) in ('EURGBP' as EURGBP
, 'EURPLN' as EURPLN
, 'EURUSD' as EURUSD)
)
order by 1
Алиасы полей, помеченные зелёным фоном -- обязательны
Вот таблица для тестирования
create table RATES (
CURPAIR varchar2(16) not null,
SNAPDATE date not null,
QOPEN number not null,
QMAX number not null,
QMIN number not null,
QCLOSE number not null,
QVOLUME number not null);
И её заполнение
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:00', 'YYYY.MM.DD HH24:MI') ,0.7208,0.721,0.7208,0.721,5 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:01', 'YYYY.MM.DD HH24:MI') ,0.7209,0.721,0.7209,0.721,4 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:02', 'YYYY.MM.DD HH24:MI') ,0.7211,0.7211,0.7209,0.721,8 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:03', 'YYYY.MM.DD HH24:MI') ,0.7209,0.721,0.7209,0.7209,5 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:04', 'YYYY.MM.DD HH24:MI') ,0.721,0.721,0.7209,0.7209,2 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:05', 'YYYY.MM.DD HH24:MI') ,0.721,0.721,0.721,0.721,1 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:06', 'YYYY.MM.DD HH24:MI') ,0.7209,0.721,0.7209,0.7209,5 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:07', 'YYYY.MM.DD HH24:MI') ,0.721,0.721,0.7209,0.7209,14 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURGBP', to_date ('2015.05.14 00:08', 'YYYY.MM.DD HH24:MI') ,0.721,0.721,0.7209,0.7209,4 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:00', 'YYYY.MM.DD HH24:MI') ,4.0937,4.0947,4.0937,4.0947,2 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:01', 'YYYY.MM.DD HH24:MI') ,4.0946,4.0946,4.0946,4.0946,1 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:02', 'YYYY.MM.DD HH24:MI') ,4.0947,4.0954,4.0947,4.0954,5 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:03', 'YYYY.MM.DD HH24:MI') ,4.0966,4.0966,4.0966,4.0966,3 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:04', 'YYYY.MM.DD HH24:MI') ,4.0955,4.0993,4.0955,4.0961,11 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:05', 'YYYY.MM.DD HH24:MI') ,4.0964,4.0973,4.0961,4.0973,7 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:06', 'YYYY.MM.DD HH24:MI') ,4.0974,4.0976,4.0974,4.0976,2 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:07', 'YYYY.MM.DD HH24:MI') ,4.0974,4.0974,4.0973,4.0973,2 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:08', 'YYYY.MM.DD HH24:MI') ,4.0974,4.0974,4.0973,4.0973,2 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURPLN', to_date ('2015.05.14 00:09', 'YYYY.MM.DD HH24:MI') ,4.0974,4.0974,4.0974,4.0974,1 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:00', 'YYYY.MM.DD HH24:MI') ,1.1352,1.1354,1.1351,1.1353,6 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:01', 'YYYY.MM.DD HH24:MI') ,1.1354,1.1355,1.1353,1.1355,14 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:02', 'YYYY.MM.DD HH24:MI') ,1.1354,1.1355,1.1354,1.1355,8 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:03', 'YYYY.MM.DD HH24:MI') ,1.1354,1.1355,1.135,1.1351,9 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:05', 'YYYY.MM.DD HH24:MI') ,1.1352,1.1352,1.1352,1.1352,1 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:06', 'YYYY.MM.DD HH24:MI') ,1.1351,1.1352,1.1351,1.1351,3 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:07', 'YYYY.MM.DD HH24:MI') ,1.1352,1.1352,1.1351,1.1352,3 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:08', 'YYYY.MM.DD HH24:MI') ,1.1351,1.1352,1.1351,1.1351,3 );
insert into RATES (CURPAIR, SNAPDATE, QOPEN, QMAX, QMIN, QCLOSE, QVOLUME) values ('EURUSD', to_date ('2015.05.14 00:09', 'YYYY.MM.DD HH24:MI') ,1.135,1.1351,1.135,1.1351,4 );
commit;
Комментариев нет:
Отправить комментарий