2012-11-02 14 views
6

gibt es so etwas in Orakel listunagg Funktion? Zum Beispiel, wenn ich ein Daten wie habe:listunagg Funktion?

------------------------------------------------------------ 
| 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   | 
-------------------------------------------------------------- 

und ich mag Daten wie diese zeigen:

----------------------------------------------- 
| 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  | 
----------------------------------------------- 

Ich habe versucht, eine Funktion wie Gegenteil von listagg zu finden, aber nicht finden kann, irgendein. Vielen Dank im Voraus :-)

+0

nein, es gibt keine solche native Funktion. nur benutzerdefinierte Umgehungslösungen –

+1

mögliche Duplikate von [Wie Konvertieren von CSV zu Tabelle in Oracle] (http://StackOverflow.com/Questions/3142665/How-to-convert-csv-to-Table-in-Oracle) – APC

Antwort

7

Wie @be hier jetzt schon im Kommentar vermerkt hat, bietet Oracle eine solche Funktion nicht an. Um eine schnelle Abhilfe könnte man ähnliche Abfrage schreiben:

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 

Ergebnis:

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

Vielen Dank das ist was ich brauchte :-) – Jaanna

0

Um unagg eine Liste überlegen, was Tom bei Oracle zu sagen hat "Tom fragen" sehen http://www.oracle.com/technetwork/issue-archive/2007/07-mar/o27asktom-084983.html Code Listing 3 oder 4.

Meine bevorzugte Option, die Tom nicht diskutiert, ist gut für kurze Zeichenfolgen (< 34 Zeichen). Ich verwende die Oracle DBMS_UTILITY.comma_to_table-Funktion. Beispiel:

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;