giovedì 16 luglio 2015

RDBMS ORACLE - String Aggregation Techniques

Per orizzontalizzare i dati esistono differenti metodi più o meno performanti o con qualche limitazione, di seguito ne vedremo alcuni.

Per capirci supponiamo di avere una tabella cosi formata:

SELECT CUBEID,CUBESETID FROM APPO_GR_TEST;

CUBEID          CUBESETID
--------------- ----------
TEST_TAAE0250   TEST_001  
TEST_TBDE0050   TEST_001  
TEST_TBDE0060   TEST_001  
TEST_TBDE0070   TEST_001  
TEST_TBDE0080   TEST_001  
TEST_TBDE0085   TEST_001  
TEST_TBDE0090   TEST_001  
TEST_TBDE0230   TEST_001  
TEST_TBDE0270   TEST_001  
TEST_TBDE0300   TEST_001  
TEST_TBDE0310   TEST_001  
TEST_TBDE0320   TEST_001  
TEST_TBDE0400   TEST_001  
TEST_TIAA0100   TEST_001  
TEST_TIAA0200   TEST_001  
TEST_TIAA0300   TEST_001  
TEST_TIAA0400   TEST_001  
TEST_TIAA0450   TEST_001  
TEST_TIAA0500   TEST_001  


Quello che vogliamo orizzontalizzare è il contenuto del campo CUBEID magari mettendo una "," tra un cubo e l'altro. Allora possiamo utilizzare per fare questa orizzontalizzazione diverse funzioni Oracle, di seguito alcune di queste funzioni.


FUNZIONE LISTAGG

Dalla versione 11g è presente una funzione che permette di orizzontalizzare i dati che all'interno di una tabella risultano essere verticalizzati.




Allora per orizzontalizzare eseguiamo la seguente query:

SELECT LENGTH(LISTAGG(CUBEID, ',') WITHIN GROUP (ORDER BY CUBESETID)) LL,
       LISTAGG(CUBEID, ',') WITHIN GROUP (ORDER BY CUBESETID) LIST
from APPO_GR_TEST where CUBESETID='TEST_001'  ;


        LL LIST        
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
       265 TEST_TAAE0250,TEST_TBDE0050,TEST_TBDE0060,TEST_TBDE0070,TEST_TBDE0080,TEST_TBDE0085,TEST_TBDE0090,TEST_TBDE0230,TEST_TBDE0270,TEST_TBDE0300,TEST_TBDE0310,TEST_TBDE0320,TEST_TBDE0400,TEST_TIAA0100,TEST_TIAA0200,TEST_TIAA0300,TEST_TIAA0400,TEST_TIAA0450,TEST_TIAA0500


Abbiamo ottenuto una stringa concatenata, l'unico inconveniente è però che se la lunghezza della
stringa supera i 4000 caratteri avremo un errore in quanto la funzione ritorna un VARCHAR2 e non un CLOB.

Report error -
Errore SQL: ORA-01489: Il risultato della concatenazione della stringa è troppo lungo
01489. 00000 -  "result of string concatenation is too long"
*Cause:    String concatenation result is more than the maximum size.
*Action:   Make sure that the result is less than the maximum size.


FUNZIONE WM_CONCAT

Altra funzione che possiamo utilizzare per orizzontalizzare è stata sviluppata per l'option del db chiamata OWM (Oracle Workspace Manager).
A differenza di quella indicata sopra, questa è presente in oracle dalla versione 10g però deve essere utilizzata con una group by e risulta meno performante rispetto alla precedente inoltre non è possibile modificare il carattere separatore che in questo caso è sempre ",", mentre nella funzione precedente poteva essere qualsiasi cosa.

SELECT CUBESETID, WMSYS.WM_CONCAT(CUBEID) AS LIST    
 FROM   APPO_GR_TEST    
GROUP  BY  CUBESETID;

CUBESETID    LIST      
------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TEST_001     TEST_TAAE0250,TEST_TIAA0500,TEST_TIAA0450,TEST_TIAA0400,TEST_TIAA0300,TEST_TIAA0200,TEST_TIAA0100,TEST_TBDE0400,TEST_TBDE0320,TEST_TBDE0310,TEST_TBDE0300,TEST_TBDE0270,TEST_TBDE0230,TEST_TBDE0090,TEST_TBDE0085,TEST_TBDE0080,TEST_TBDE0070,TEST_TBDE0060,TEST_TBDE0050


FUNZIONE COLLECT

Dalla versione 10g è presente anche un'altra funzione la COLLECT che però ha un utilizzo un pò più complesso, in quanto occorre prima definire un TYPE.
Vediamo come si utilizza:

CREATE OR REPLACE TYPE varchar2_gr AS TABLE OF VARCHAR2(4000);
 

 TYPE VARCHAR2_GR compilato
 

SELECT CUBESETID, CAST(COLLECT(CUBEID) AS varchar2_gr)  AS LIST
 FROM   APPO_GR_TEST
GROUP  BY CUBESETID;

 

CUBESETID  LIST
---------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TEST_001   WRES049.VARCHAR2_GR('TEST_TAAE0250','TEST_TIAA0500','TEST_TIAA0450','TEST_TIAA0400','TEST_TIAA0300','TEST_TIAA0200','TEST_TIAA0100','TEST_TBDE0400','TEST_TBDE0320','TEST_TBDE0310','TEST_TBDE0300','TEST_TBDE0270','TEST_TBDE0230','TEST_TBDE0090','TEST_TBDE0085','TEST_TBDE0080','TEST_TBDE0070','TEST_TBDE0060','TEST_TBDE0050')




Altre opzioni per orizzontalizzare il daro sarebbe lo sviluppo di funzioni ma questo comporta quindi l'utilizzo di funzioni non native di oracle.
Alcuni esempi li trovate qui:

https://oracle-base.com/articles/misc/string-aggregation-techniques


























Nessun commento:

Posta un commento