2012-11-02 13 views
6

c'è una cosa simile in oracolo come la funzione listunagg? Per esempio, se ho un di dati come:funzione listunagg?

------------------------------------------------------------ 
| user_id | degree_fi | degree_en  | degree_sv  | 
-------------------------------------------------------------- 
| 3601464 | 3700   | 1600   | 2200   | 
| 1020 | 100   | 0    | 0    | 
| 3600520 | 100,3200,400 | 1300, 800, 3000 | 1400, 600, 1500 | 
| 3600882 | 0   | 100   | 200   | 
-------------------------------------------------------------- 

e mi piacerebbe per visualizzare i dati in questo modo:

----------------------------------------------- 
| user_id | degree_fi | degree_en | degree_sv | 
----------------------------------------------- 
| 3601464 | 3700  | 1600  | 2200  | 
| 1020 | 100  | 0  | 0  | 
| 3600520 | 100  | 1300  | 1400  | 
| 3600882 | 0  | 100  | 200  | 
| 3600520 | 3200  | 800  | 600  | 
| 3600520 | 400  | 3000  | 1500  | 
----------------------------------------------- 

Ho cercato di trovare una qualche funzione, come opposto di listagg ma non ho trovato qualunque. Grazie in anticipo :-)

+0

no, non esiste tale funzione nativa. solo soluzioni alternative personalizzate –

+1

possibile duplicato di [come convertire csv nella tabella in oracle] (http://stackoverflow.com/questions/3142665/how-to-convert-csv-to-table-in-oracle) – APC

risposta

7

Come @be qui ora ha già notato nel commento Oracle non fornisce tale funzione. Così come una soluzione rapida si potrebbe scrivere query simile:

with t1(user_id, degree_fi, degree_en, degree_sv) as 
(
    select 3601464, '3700', '1600', '2200' from dual union all 
    select 1020 , '100' , '0' , '0' from dual union all 
    select 3600520, '100,3200,400', '1300, 800, 3000', '1400, 600, 1500' from dual union all 
    select 3600882, '0', '100', '200' from dual 
), 
Occurence(ocr) as(
    select Level as ocr 
    from (select max(greatest(regexp_count(degree_fi, '[^,]+') 
          , regexp_count(degree_en, '[^,]+') 
          , regexp_count(degree_sv, '[^,]+') 
          ) 
        ) mx 
      from t1  
     ) 
    connect by level <= mx 
) 
select * 
    from (
select User_id 
    , regexp_substr(degree_fi, '[^,]+', 1, o.ocr) as degree_fi 
    , regexp_substr(degree_en, '[^,]+', 1, o.ocr) as degree_en 
    , regexp_substr(degree_sv, '[^,]+', 1, o.ocr) as degree_sv 
    from t1 t 
    cross join Occurence o 
) 
where degree_fi is not null 
    or degree_en is not null 
    or degree_sv is not null 

Risultato:

User_Id Degree_Fi Degree_En Degree_Sv 
------------------------------------------------------------ 
3601464 3700  1600  2200 
1020  100  0   0 
3600520 100  1300  1400 
3600882 0   100  200 
3600520 3200  800  600 
3600520 400  3000  1500 
+1

Grazie quello di cui avevo bisogno :-) – Jaanna

0

Per unagg un elenco in considerazione ciò che Tom ha da dire a Oracle di "Chiedi Tom" vedere http://www.oracle.com/technetwork/issue-archive/2007/07-mar/o27asktom-084983.html Codice 3 o 4.

La mia opzione preferita che Tom non discute è buona per le stringhe brevi (< 34 caratteri). Uso la funzione Oracle DBMS_UTILITY.comma_to_table. Esempio:

SET SERVEROUTPUT ON 
DECLARE 
/** test data **/ 
    L_LIST1 VARCHAR2(500) := '"A","B","C","Pierre - Andre","D","E","OFVampFVapos;CBryan","F","G","H","I","J"'; 
    l_list2 VARCHAR2(500); 
    l_tablen BINARY_INTEGER; 
    l_tab  DBMS_UTILITY.uncl_array; 
BEGIN 
    DBMS_OUTPUT.put_line('l_list1 : ' || l_list1); 

    DBMS_UTILITY.comma_to_table (
    list => l_list1, 
    tablen => l_tablen, 
    tab => l_tab); 

    FOR i IN 1 .. l_tablen LOOP 
    DBMS_OUTPUT.put_line(i || ' : ' || l_tab(i)); 
    END LOOP; 

    DBMS_UTILITY.table_to_comma (
    tab => l_tab, 
    tablen => l_tablen, 
    list => l_list2); 

    DBMS_OUTPUT.put_line('l_list2 : ' || l_list2); 
end;