Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comment convertir des valeurs séparées par des virgules en lignes dans Oracle ?

Je reconnais qu'il s'agit d'un très mauvais design. Essayez ceci si vous ne pouvez pas modifier ce 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;

SORTIE

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

Crédits à ceci

Pour supprimer les doublons de manière plus élégante et efficace (crédits à @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;

Si vous souhaitez une approche "ANSIer", optez pour un 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;

SORTIE

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

Une autre approche récursive par MT0 mais sans 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;

J'ai essayé 3 approches avec un jeu de données de 30 000 lignes et 118 104 lignes renvoyées, et j'ai obtenu les résultats moyens suivants :

  • Mon approche récursive :5 secondes
  • Approche MT0 :4 secondes
  • Approche Mathguy :16 secondes
  • Approche récursive MT0 sans expression régulière :3,45 secondes

@Mathguy a également testé avec un jeu de données plus important :

Dans tous les cas, la requête récursive (je n'ai testé que celle avec regularsubstr et instr) fait mieux, par un facteur de 2 à 5. Voici les combinaisons de # de chaînes / jetons par chaîne et les temps d'exécution CTAS pour hiérarchique vs récursif, hiérarchique d'abord . Toutes les fois en secondes

  • 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