I have an existing table like :
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);
And I have that pivots rows to columns like this, that returns the desired output :
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
Now, with some evolution the table ES_DEVISES
will contain random units (ES1, ES2, ES3, ...) and random currencies (USD, EUR, XRP, BTC, ...) so the query above won't be valid anymore. I found this answer that recommends using PIVOT XML
so the query became :
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>
The next step now is to parse that XML so I can get back to a result set that looks like the first output. The problem now is that the DEVISE_XML
field doesn't contain the NOM
field and I couldn't find a way to parse the XML to dynamic columns, I tried to use XMLTABLE
but it gets me back to something like SELECT * FROM ES_DEVISES
.
My question is : is there any way to either :
1) return an XML looking like this :
<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) Parse the XML to return the desired output (which should look like the output from the first query) dynamically.
PS : I saw many solutions in the net like using LISTAGG
or building the query with a string and executing it with EXECUTE IMMEDIATE
. But none of that interest me because I could just easily do it with JAVA but the aim of this question is to find a clear, easily maintainable query that's doing all the job from a PROCEDURE
.