将分隔的 table 拆分为行

Splitting delimited table into rows

我有一些与此非常相似的数据:

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

当然,每行中值的数量可以从 1 到 n。我仅针对 1 列找到了一些关于此的建议(使用 Connect by with regexp_substr)

有什么方法(SQL 或 PL/SQL 明智)获得所需的输出:

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

谢谢

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                    

不确定在大表上的性能,但是这个 select 应该可以工作

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;