sql >> Database >  >> RDS >> Oracle

Hoe door komma's gescheiden waarden naar rijen in orakel te converteren?

Ik ben het ermee eens dat dit een heel slecht ontwerp is. Probeer dit als je dat ontwerp niet kunt veranderen:

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;

UITGANG

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

Credits hiervoor

Om duplicaten op een elegantere en efficiëntere manier te verwijderen (met dank aan @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;

Als u een "ANSIer"-aanpak wilt, kies dan voor een 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;

UITVOER

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

Een andere recursieve benadering door MT0 maar zonder regex:

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;

Ik heb 3 benaderingen geprobeerd met een dataset van 30000 rijen en 118104 rijen geretourneerd en kreeg de volgende gemiddelde resultaten:

  • Mijn recursieve benadering:5 seconden
  • MT0-benadering:4 seconden
  • Mathguy-benadering:16 seconden
  • MT0 recursieve benadering zonder regex:3,45 seconden

@Mathguy heeft ook getest met een grotere dataset:

In alle gevallen doet de recursieve query (ik heb alleen die met regularsubstr en instr getest) het beter, met een factor 2 tot 5. Hier zijn de combinaties van # strings / tokens per string en CTAS-uitvoeringstijden voor hiërarchisch versus recursief, hiërarchisch eerst . Alle tijden in seconden

  • 30.000 x 4:5 / 1.
  • 30.000 x 10:15 / 3.
  • 30.000 x 25:56 / 37.
  • 5,000 x 50:33 / 14.
  • 5,000 x 100:160 / 81.
  • 10.000 x 200:1.924 / 772


  1. Index viel buiten de grenzen van de array. (Microsoft.SqlServer.smo)

  2. Hoe definieer je een trigger ON COMMIT in Oracle?

  3. Tekstcompressie in PostgreSQL

  4. MySQL-gebruikersmachtigingen