sql >> Databasteknik >  >> RDS >> Oracle

Hur konverterar man kommaseparerade värden till rader i Oracle?

Jag håller med om att detta är en riktigt dålig design. Testa detta om du inte kan ändra den designen:

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;

OUTPUT

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

Tack till detta

För att ta bort dubbletter på ett mer elegant och effektivt sätt (krediter till @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;

Om du vill ha en "ANSIer"-strategi, använd en 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;

OUTPUT

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

Ett annat rekursivt tillvägagångssätt av MT0 men utan 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;

Jag har provat tre metoder med en datauppsättning på 30 000 rader och 118 104 rader returnerade och fick följande genomsnittliga resultat:

  • Mitt rekursiva tillvägagångssätt:5 sekunder
  • MT0-tillvägagångssätt:4 sekunder
  • Mathguy approach:16 sekunder
  • MT0 rekursivt tillvägagångssätt utan regex:3,45 sekunder

@Mathguy har också testat med en större datauppsättning:

I alla fall fungerar den rekursiva frågan (jag testade bara den med regularsubstr och instr) bättre, med en faktor på 2 till 5. Här är kombinationerna av # strängar/tokens per sträng och CTAS-körningstider för hierarkisk kontra rekursiv, hierarkisk först . Alla gånger på några sekunder

  • 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. Nästan noll driftstopp automatiska uppgraderingar av PostgreSQL-kluster i moln (del I)

  2. SQL Ordning efter antal

  3. JSON_PRETTY() – Formatera JSON-dokument för enklare läsbarhet i MySQL

  4. Hur RPAD()-funktionen fungerar i MySQL