sql >> Database teknologi >  >> RDS >> Oracle

Hvordan konverteres kommaseparerede værdier til rækker i oracle?

Jeg er enig i, at dette er et rigtig dårligt design. Prøv dette, hvis du ikke kan ændre det design:

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;
 

UDGANG

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
 

Tak til dette

For at fjerne dubletter på en mere elegant og effektiv måde (kreditter til @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;
 

Hvis du ønsker en "ANSIer"-tilgang, så tag 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
 

En anden rekursiv tilgang af MT0, men uden 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;

Jeg har prøvet 3 tilgange med et 30.000 rækker datasæt og 118104 rækker returneret og fik følgende gennemsnitlige resultater:

  • Min rekursive tilgang:5 sekunder
  • MT0-tilgang:4 sekunder
  • Mathguy tilgang:16 sekunder
  • MT0 rekursiv tilgang uden regex:3,45 sekunder

@Mathguy har også testet med et større datasæt:

I alle tilfælde klarer den rekursive forespørgsel (jeg testede kun den med regularsubstr og instr) det bedre, med en faktor på 2 til 5. Her er kombinationerne af # af strenge/tokens pr. streng og CTAS-udførelsestider for hierarkisk vs. rekursiv, hierarkisk først . Alle gange i 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. Sådan tilføjer du primær nøglebegrænsning til identitetskolonner til alle tabellerne i SQL Server-databasen - SQL Server / TSQL Selvstudium Del 63

  2. CTE for at få alle børn (efterkommere) af en forælder

  3. Sådan vælger du dato uden tid i SQL

  4. Find overtrædelser af fremmednøgler i SQLite