2017-08-14 1 views
0

J'ai des données très similaires à ceci:Fractionnement table délimitée par des lignes en

ID STATUS     EMPL 
1 Created;Solved;Closed John;Terry;Martin 

Bien sûr, le nombre de valeurs dans chaque ligne peut varier de 1 à n. J'ai trouvé quelques conseils sur ce pour 1 seule colonne (en utilisant Connect par avec regexp_substr)

Est-il possible (SQL ou PL/SQL sage) pour obtenir la sortie désirée:

ID STATUS EMPL 
1 Created John 
1 Solved Terry 
1 Closed Martin 

Merci

+0

Ecrire une fonction ou SP. Avoir un curseur dedans et faire une boucle avec chaque rangée. Sur chaque ligne, divisez vos données avec (;) comme indiqué dans la question. Maintenant, ayez une table temporaire et continuez à ajouter. – Prathyush

+0

Cela serait beaucoup plus facile à gérer dans votre couche d'application, par exemple. Java. Les bases de données ne sont pas les meilleurs endroits pour nettoyer vos données. –

+0

Tout d'abord normaliser ou au moins utiliser le type de collection. L'utilisation de CSV est une très mauvaise idée. – lad2025

Répondre

0

Pas sûr de la performance sur les grandes tables mais cette sélection devrait fonctionner

select st.id, st.status, em.empl from (
    select distinct id, level as lvl, regexp_substr(status,'[^;]+',1,level) as status 
    from to_split connect by regexp_substr(status,'[^;]+',1,level) is not null 
) st 
join (
    select distinct id, level as lvl, regexp_substr(empl,'[^;]+',1,level) as empl 
    from to_split connect by regexp_substr(empl,'[^;]+',1,level) is not null 
) em 
on st.id = em.id and st.lvl = em.lvl 
order by id; 
2
with d (id, status, empl) as 
(
    select 1 ,'Created;Solved;Closed',     'John;Terry;Martin'   from dual union all 
    select 2 ,'Created2;Reviewed2;Solved2;Closed2', 'John2;Bell2;Terry2;Martin2' from dual 
) 
,cte(id, status, s, e, empl, s1, e1, rn) as 
(
    select 
    id, status, 1, case when instr(status, ';') > 0 then instr(status, ';') else length(status)+1 end, 
      empl, 1, case when instr(empl, ';') > 0 then instr(empl, ';') else length(empl)+1 end, 0 
    from d 
    union all 
    select 
    id, status, e+1, case when instr(status, ';' , e+1) > 0 then instr(status, ';', e+1) else length(status)+1 end, 
      empl, e1+1, case when instr(empl, ';' , e1+1) > 0 then instr(empl, ';', e1+1) else length(empl)+1 end, rn+1 
    from cte where e <= length(status) 
    -- assumption: equal number of delimiters (;) in status and empl column values 
) 
select id, substr(status, s, e - s) status, substr(empl, s1, e1 - s1) empl from cte 
order by id,rn 
; 

     ID STATUS        EMPL      
---------- ---------------------------------- -------------------------- 
     1 Created       John      
     1 Solved        Terry      
     1 Closed        Martin      
     2 Created2       John2      
     2 Reviewed2       Bell2      
     2 Solved2       Terry2      
     2 Closed2       Martin2