【问题标题】:Splitting delimited table into rows将分隔表拆分为行
【发布时间】:2017-08-14 07:49:49
【问题描述】:

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

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

谢谢

【问题讨论】:

  • 写一个函数或SP。在其中有一个游标并遍历每一行。在每一行上,用 (;) 拆分您的数据,如问题所示。现在有一个临时表并继续添加。
  • 这将在您的应用层中非常更容易处理,例如爪哇。数据库不是清理数据的最佳场所。
  • 首先规范化或至少使用集合类型。使用 CSV 是一个非常糟糕的主意。
  • @TimBiegeleisen - 我意识到这并不理想,但这就是我工作的公司的做法 - 我无能为力......
  • 我同意@TimBiegeleisen,拥有前端代码会很好。如果您有任何阻碍您的政策,请使用 SQL 选项。

标签: sql oracle plsql delimiter


【解决方案1】:
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                    

【讨论】:

    【解决方案2】:

    不确定大表的性能,但这个选择应该可以工作

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      • 1970-01-01
      • 2019-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多