2012-11-02 12 views
6

czy jest coś takiego w funkcji orunch jak listunagg? Na przykład, jeśli mam danych, takich jak:funkcja 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   | 
-------------------------------------------------------------- 

i chciałbym pokazać dane tak:

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

Próbowałem znaleźć jakąś funkcję jak przeciwieństwo listagg ale nie mógł znaleźć każdy. Z góry dziękuję :-)

+0

Nie, nie ma takiej natywnej funkcji. tylko niestandardowe obejścia –

+1

możliwy duplikat [jak przekonwertować csv na tabelę w oracle] (http://stackoverflow.com/questions/3142665/how-to-convert-csv-to-table-in-oracle) – APC

Odpowiedz

7

Jak już wspomniano w komentarzu, Oracle nie zapewnia takiej funkcji. Tak szybkiego obejścia można napisać podobną zapytanie:

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 

Wynik:

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

Dzięki temu czego potrzebowałem :-) – Jaanna

0

Aby unagg listę rozważyć, co Tom ma do powiedzenia na Oracle "Zapytaj Toma" zobaczyć http://www.oracle.com/technetwork/issue-archive/2007/07-mar/o27asktom-084983.html Listing 3 lub 4.

Moja preferowana opcja, której Tom nie omawia, jest dobra w przypadku krótkich łańcuchów znaków (< 34 znaki). Używam funkcji Oracle DBMS_UTILITY.comma_to_table. Przykład:

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;