Обойти проблему Oracle Dynamic Pivot с использованием XML - PullRequest
1 голос
/ 11 июня 2019

У меня есть существующая таблица, например:

CREATE TABLE ES_DEVISES (
  NOM VARCHAR2(500),
  DEVISE VARCHAR2(5),
  ORDRES NUMBER(5,0)
)
-- For testing purposes :
INSERT INTO ES_DEVISES VALUES ('ES1','CHF',157);
INSERT INTO ES_DEVISES VALUES ('ES1','USD',1328);
INSERT INTO ES_DEVISES VALUES ('ES2','AUD',5);
INSERT INTO ES_DEVISES VALUES ('ES1','AUD',23);
INSERT INTO ES_DEVISES VALUES ('ES1','CNY',17);
INSERT INTO ES_DEVISES VALUES ('ES1','INR',17);
INSERT INTO ES_DEVISES VALUES ('ES2','CNY',1);
INSERT INTO ES_DEVISES VALUES ('ES2','INR',4);
INSERT INTO ES_DEVISES VALUES ('ES2','USD',218);
INSERT INTO ES_DEVISES VALUES ('ES2','CHF',42);

И у меня есть то, что выводит строки в такие столбцы, что возвращает желаемый результат:

SELECT * FROM ES_DEVISES
PIVOT (
  MAX(ORDRES) FOR DEVISE IN ('USD' USD,'CHF' CHF,'CNY' CNY,'INR' INR,'AUD' AUD)
);

-- Output :
NOM                  USD        CHF        CNY        INR        AUD
---------------- ---------- ---------- ---------- ---------- ----------
ES1                1328        157         17         17         23 
ES2                218         42          1          4          5 

Теперь, с некоторой эволюцией, таблица ES_DEVISES будет содержать случайные единицы (ES1, ES2, ES3, ...) и случайные валюты (USD, EUR, XRP, BTC, ...), поэтому приведенный выше запрос выиграет больше не будет действительным. Я нашел этот ответ , который рекомендует использовать PIVOT XML, поэтому запрос стал:

SELECT NOM, DEVISE_XML
FROM ES_DEVISES
PIVOT XML(
  MAX(ORDRES) FOR DEVISE IN (SELECT DEVISE FROM NEW_TABLE_FOR_CURRENCIES)
) t;

-- Output :
NOM              DEVISE_XML                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
---------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ES1              <PivotSet><item><column name = "DEVISE">AUD</column><column name = "MAX(ORDRES)">23</column></item><item><column name = "DEVISE">CHF</column><column name = "MAX(ORDRES)">157</column></item><item><column name = "DEVISE">CNY</column><column name = "MAX(ORDRES)">17</column></item><item><column name = "DEVISE">INR</column><column name = "MAX(ORDRES)">17</column></item><item><column name = "DEVISE">USD</column><column name = "MAX(ORDRES)">1328</column></item></PivotSet>    
ES2              <PivotSet><item><column name = "DEVISE">AUD</column><column name = "MAX(ORDRES)">5</column></item><item><column name = "DEVISE">CHF</column><column name = "MAX(ORDRES)">42</column></item><item><column name = "DEVISE">CNY</column><column name = "MAX(ORDRES)">1</column></item><item><column name = "DEVISE">INR</column><column name = "MAX(ORDRES)">4</column></item><item><column name = "DEVISE">USD</column><column name = "MAX(ORDRES)">218</column></item></PivotSet>         

Следующим шагом сейчас является анализ этого XML, чтобы я мог вернуться к результирующему набору, который выглядит как первый вывод. Проблема в том, что поле DEVISE_XML не содержит поля NOM, и я не смог найти способ разбора XML на динамические столбцы, я попытался использовать XMLTABLE, но он возвращает меня к чему-то вроде SELECT * FROM ES_DEVISES.

Мой вопрос: есть ли способ либо:

1) вернуть XML, похожий на этот:

<PivotSet>
    <row>
        <unit>ES1</unit>
        <column name="AUD">23</column>
        <column name="CHF">157</column>
        <column name="CNY">17</column>
        <column name="INR">17</column>
        <column name="USD">1328</column>
    </row>
    <row>
        <unit>ES2</unit>
        <column name="AUD">218</column>
        <column name="CHF">42</column>
        <column name="CNY">1</column>
        <column name="INR">4</column>
        <column name="USD">5</column>
    </row>
</PivotSet>

2) Анализирует XML для динамического возврата желаемого результата (который должен выглядеть как результат первого запроса).

PS: я видел много решений в сети, таких как LISTAGG или построение запроса со строкой и выполнение его с EXECUTE IMMEDIATE. Но ничего из этого меня не интересует, потому что я мог бы легко сделать это с JAVA, но цель этого вопроса - найти понятный, легко обслуживаемый запрос, который выполняет всю работу с PROCEDURE.

1 Ответ

1 голос
/ 12 июня 2019

Я использую динамическую функцию PIVOT для таких требований в моих проектах.

Я добавил еще одну строку, которая является случайной. - согласно вашему требованию.

CREATE TABLE ES_DEVISES (
  NOM VARCHAR2(500),
  DEVISE VARCHAR2(5),
  ORDRES NUMBER(5,0)
);
-- For testing purposes :
INSERT INTO ES_DEVISES VALUES ('ES1','CHF',157);
INSERT INTO ES_DEVISES VALUES ('ES1','USD',1328);
INSERT INTO ES_DEVISES VALUES ('ES2','AUD',5);
INSERT INTO ES_DEVISES VALUES ('ES1','AUD',23);
INSERT INTO ES_DEVISES VALUES ('ES1','CNY',17);
INSERT INTO ES_DEVISES VALUES ('ES1','INR',17);
INSERT INTO ES_DEVISES VALUES ('ES2','CNY',1);
INSERT INTO ES_DEVISES VALUES ('ES2','INR',4);
INSERT INTO ES_DEVISES VALUES ('ES2','USD',218);
INSERT INTO ES_DEVISES VALUES ('ES2','CHF',42);
INSERT INTO ES_DEVISES VALUES ('ES3','RNDM',100); -- random record added by me


SELECT
    *
FROM
    TABLE ( PIVOT(' select NOM
                      ,      DEVISE
                      ,      MAX(ORDRES) ORDRES
                      from   ES_DEVISES
                      group
                      by     NOM
                      ,      DEVISE
                    '
    ) );

OUTPUT

Output

Здесь PIVOT - это функция , и я получил ее от МАСС.

Вот ссылка для загрузки функции: Динамический PIVOT

Извлеките загруженный zip-файл и выполните скрипт pivotFun.sql , чтобы создать функцию PIVOT в вашей БД.

Надеюсь, вам понравится.

...