Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak przekonwertować wartości oddzielone przecinkami na wiersze w Oracle?

Zgadzam się, że to naprawdę zły projekt. Spróbuj tego, jeśli nie możesz zmienić tego projektu:

select distinct id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
  from tbl1
   connect by regexp_substr(value, '[^,]+', 1, level) is not null
   order by id, level;

WYJŚCIE

id value level
1   AA  1
1   UT  2
1   BT  3
1   SK  4
1   SX  5
2   AA  1
2   UT  2
2   SX  3
3   UT  1
3   SK  2
3   SX  3
3   ZF  4

Kredyty do tego

Aby usunąć duplikaty w bardziej elegancki i wydajny sposób (kredyty dla @mathguy)

select id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
  from tbl1
   connect by regexp_substr(value, '[^,]+', 1, level) is not null
      and PRIOR id =  id 
      and PRIOR SYS_GUID() is not null  
   order by id, level;

Jeśli chcesz podejścia „ANSIer”, wybierz CTE:

with t (id,res,val,lev) as (
           select id, trim(regexp_substr(value,'[^,]+', 1, 1 )) res, value as val, 1 as lev
             from tbl1
            where regexp_substr(value, '[^,]+', 1, 1) is not null
            union all           
            select id, trim(regexp_substr(val,'[^,]+', 1, lev+1) ) res, val, lev+1 as lev
              from t
              where regexp_substr(val, '[^,]+', 1, lev+1) is not null
              )
select id, res,lev
  from t
order by id, lev;

WYJŚCIE

id  val lev
1   AA  1
1   UT  2
1   BT  3
1   SK  4
1   SX  5
2   AA  1
2   UT  2
2   SX  3
3   UT  1
3   SK  2
3   SX  3
3   ZF  4

Kolejne podejście rekurencyjne przez MT0, ale bez wyrażenia regularnego:

WITH t ( id, value, start_pos, end_pos ) AS
  ( SELECT id, value, 1, INSTR( value, ',' ) FROM tbl1
  UNION ALL
  SELECT id,
    value,
    end_pos                    + 1,
    INSTR( value, ',', end_pos + 1 )
  FROM t
  WHERE end_pos > 0
  )
SELECT id,
  SUBSTR( value, start_pos, DECODE( end_pos, 0, LENGTH( value ) + 1, end_pos ) - start_pos ) AS value
FROM t
ORDER BY id,
  start_pos;

Wypróbowałem 3 podejścia z zestawem danych 30000 wierszy i zwróconymi 118104 wierszami i uzyskałem następujące średnie wyniki:

  • Moje podejście rekurencyjne:5 sekund
  • Podejście MT0:4 sekundy
  • Podejście Mathguy:16 sekund
  • Podejście rekurencyjne MT0 bez wyrażenia regularnego:3,45 sekundy

@Mathguy przetestował również z większym zbiorem danych:

We wszystkich przypadkach zapytanie rekurencyjne (testowałem tylko to z regularsubstr i instr) działa lepiej, o współczynnik od 2 do 5. Oto kombinacje liczby ciągów / tokenów na ciąg i czasów wykonania CTAS dla hierarchii i rekurencji, najpierw hierarchicznie . Cały czas w sekundach

  • 30 000 x 4:5 / 1.
  • 30 000 x 10:15/3.
  • 30 000 x 25:56 / 37.
  • 5000 x 50:33 / 14.
  • 5000 x 100:160 / 81.
  • 10 000 x 200:1924/772


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wprowadzenie do zbiorczego zbierania danych PL/SQL w bazie danych Oracle

  2. Alternatywy dla LIMIT i OFFSET dla stronicowania w Oracle

  3. Oracle ORA-30004 przy użyciu funkcji SYS_CONNECT_BY_PATH,

  4. Lista parametrów NLS w bazie danych Oracle

  5. Jak rozwiązać ORA-29913 za pomocą tabel zewnętrznych