Oracle
 sql >> база данни >  >> RDS >> Oracle

Как да конвертирам стойности, разделени със запетая, в редове в Oracle?

Съгласен съм, че това е наистина лош дизайн. Опитайте това, ако не можете да промените този дизайн:

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;

ИЗХОД

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

Заслуги за това

За премахване на дубликати по по-елегантен и ефективен начин (кредит на @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;

Ако искате "ANSIer" подход, използвайте 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;

ИЗХОД

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

Друг рекурсивен подход от MT0, но без регулярен израз:

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;

Опитах 3 подхода с набор от данни от 30000 реда и върнати 118104 реда и получих следните средни резултати:

  • Моят рекурсивен подход:5 секунди
  • MT0 подход:4 секунди
  • Подход на Mathguy:16 секунди
  • MT0 рекурсивен подход без регулярен израз:3,45 секунди

@Mathguy също тества с по-голям набор от данни:

Във всички случаи рекурсивната заявка (тествах само тази с regularsubstr и instr) се справя по-добре, с коефициент от 2 до 5. Ето комбинациите от # низове/токени на низ и времена на изпълнение на CTAS за йерархично спрямо рекурсивно, йерархично първо . Всички времена в секунди

  • 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. Последователност на Oracle, започваща с 2 вместо с 1

  2. оракул | изтриване на дублиращи се записи

  3. Когато изпълнява скрипт на SQLPlus, той отпечатва поредица от числа вместо изход

  4. Oracle сравнява времеви печат с дата

  5. Леко приключение за покупка