使用XML解决Oracle Dynamic Pivot问题

时间:2019-06-11 14:25:05

标签: oracle pivot oracle12c

我有一个现有的表,例如:

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等),因此上面的查询将不再有效。我发现this answer建议使用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 个答案:

答案 0 :(得分:1)

我正在为项目中的此类需求使用动态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

在这里, PIVOT是功能,我是从AMIS获得的。

以下是下载功能的链接:Dynamic PIVOT

解压缩下载的zip并执行脚本 pivotFun.sql 在数据库中创建PIVOT函数。

希望,您会喜欢它。