拆分多列分号分隔的字符串并创建记录

Posted

技术标签:

【中文标题】拆分多列分号分隔的字符串并创建记录【英文标题】:Split multi column semicolon separated string and create records 【发布时间】:2012-11-21 08:38:39 【问题描述】:

我有一个接收三个字符串参数的存储过程

1. p_ReqIDs VARCHAR2
2. p_ItemIDs VARCHAR2
3. p_Qtys    VARCHAR2

以上 3 个字符串变量包含分号分隔的值,如下所示:

p_ReqIDs  := "56;56;56;"  
p_ItemIDs := "3;2;1;"  
p_Qtys    := "400;300;200;"  

我需要像这样拆分值并创建行:

p_ReqIDs   p_ItemIDs   p_Qtys  
------------------------------------
  56           3       400  
  56           2       300  
  56           1       200  

我还需要拆分并插入表格的查询。

谢谢

【问题讨论】:

【参考方案1】:

您可以按如下方式处理参数:

SQL> declare
  2    type l_rec_type is record(
  3      r_ReqIDs  varchar2(31),
  4      r_ItemIDs varchar2(31),
  5      r_Qtys    varchar2(31)
  6    );
  7  
  8    type l_rec_list is table of l_rec_type;
  9    -- your parameters. 
 10    l_ReqIDs  constant varchar2(31) := '56;56;56;';
 11    l_ItemIDs constant varchar2(31) := '3;2;1;';
 12    l_Qtys    constant varchar2(31) := '400;300;200;';
 13  
 14    l_rec l_rec_list;
 15  begin
 16  
 17  with Parameters(param) as(
 18      select l_ReqIDs  from dual union all
 19      select l_ItemIDs from dual union all
 20      select l_Qtys    from dual
 21    ),
 22    Occurrences(oc) as(
 23      select level
 24        from ( select max(regexp_count(param, '[^;]+')) moc
 25                 from parameters) s
 26     connect by level <= s.moc
 27    )
 28  select max(res1)
 29       , max(res2)
 30       , max(res3)
 31    bulk collect into l_rec
 32    from (select decode(param, l_ReqIDs, res) res1
 33               , decode(param, l_ItemIDs,res) res2
 34               , decode(param, l_Qtys,   res) res3
 35               , rn
 36            from ( select param, regexp_substr(param, '[^;]+', 1, o.oc) res
 37                        , row_number() over(partition by param order by param) rn
 38                     from parameters p
 39                    cross join occurrences o
 40                  )
 41          )
 42  group by rn;
 43  
 44    for i in l_rec.first..l_rec.last
 45    loop
 46       dbms_output.put_line(l_rec(i).r_ReqIDs || '  ' || l_rec(i).r_ItemIDs || '  ' || l_rec(i).r_Qtys);
 47    end loop;
 48  end;
 49  /



56   2   200
56   1   300
56   3   400

PL/SQL procedure successfully completed

如果您只需要将处理后的数据插入表中,则只需要 insert into 语句和查询(bulk collect into l_rec 必须删除):

insert into your_table(<<columns>>)
  with Parameters(param) as(
     select l_ReqIDs  from dual union all
     select l_ItemIDs from dual union all
     select l_Qtys    from dual
  .... 
  -- the rest of the query from the above pl/sql block.

您还可以将整条记录插入到表中(如果您需要在插入之前对提取的元素进行额外处理),如下所示:

如果表中的列数等于插入的元素数

for i in l_rec.first..l_rec.last
loop
   insert into your_table
     values l_rec(i);
end loop;

如果表中的列数大于插入的值数

for i in l_rec.first..l_rec.last
loop
   insert into (select column1, .. ,columnn from your_table)
     values l_rec(i);
end loop;

【讨论】:

【参考方案2】:

我确实喜欢这个 :) 简短而甜蜜。

create or replace procedure proc1(p_ReqID varchar2,p_ItemID varchar2,p_ItemQty varchar2)
is
begin
 insert into test(req_id,item_id,itemqty)
 select regexp_substr(req_id,'[^;]+',1,level),
         regexp_substr(item_id,'[^;]+',1,level),
         regexp_substr(item_qty,'[^;]+',1,level)
  from  (
      select p_ReqID Req_ID,p_ItemID item_id,p_ItemQty item_qty
      from dual
      )
  connect by regexp_substr(req_id,'[^;]+',1,level) is not null;
end;

【讨论】:

是的,它更短。您只需要在connect by 子句中为每个参数添加OR 条件,以防第二个或第三个等参数具有比第一个更多的元素。否则你可能会丢失有价值的信息:) Nicholas 在我的情况下它永远不会发生,因为我正在提取相同 REQ_ID 的详细记录并传递给 Oracle 的 .NET Web 服务。所以所有的列总是有相同的值:)

以上是关于拆分多列分号分隔的字符串并创建记录的主要内容,如果未能解决你的问题,请参考以下文章

Pandas使用split函数基于指定分隔符拆分数据列的内容为列表设置expand参数将拆分结果列表内容转化为多列数据并添加到原数据中replace函数基于正则表达式替换字符串数据列中的匹配内容

Pandas使用split函数基于指定分隔符拆分数据列的内容为列表设置参数n控制拆分的次数设置expand参数将拆分结果列表内容转化为多列dataframe并添加到原dataframe中

在 PowerShell 中将字符串拆分为多列

拆分'$'分隔的字符串并插入到表中

Pandas使用str属性获取数据列的字符串方法类split函数基于指定分隔符拆分数据列的内容为列表设置参数n控制拆分的次数设置expand参数将拆分结果列表内容转化为多列dataframe

基于SQL Server中的分隔符将文本拆分为多列