将可变长度字符串拆分为多个列

时间:2014-09-01 10:24:52

标签: sql regex oracle

我有2个表AB。表A中的数据包含一个字符串,我希望根据"#___-"abcxyzefg等将其拆分为不同的列并将其复制进入表B。表A的字符串大小将因每行而异

表A:

Create table A ( data varchar(100));

Insert table A
  values ('101,#abc-sds)dfgd)3453)#xyz-hju)dddjfj)eieei)2323');
Insert into A
  values ('102,#abc-ddeff)errr)3434)#xyz-bnhb)hehe)333)#abc-dew)weerr)2343)#efg-3434)34');

Create table B ( id number, abc varchar2(50), xyz varchar2(50),
  efg varchar2(50));

表B的输出:

  ID  | ABC              |  XYZ                    |  EFG
  ---------------------------------------------------------------
  101 | sds)dfgd)3453)   | hju)dddjfj)eieei)2323   | 
  102 | ddeff)errr)3434) | bnhb)hehe)333)          | 3434)34
  102 | dew)weerr)2343)  | bnhb)hehe)333)          | 3434)34

我尝试了正则表达式,但由于字符串大小可能会有所不同,并且由于重复发生,我无法进一步提供任何帮助。

1 个答案:

答案 0 :(得分:0)

如果你问我认为你在问什么,你需要动态SQL 正则表达式透视即可。 动态SQL 生成代码,该代码将使表格具有适当的列(因为它们以#___-命名并且有任意数量的列)。 透视以将一列值转换为每个ID的行数。

我习惯使用SQL Server,而不是Oracle,我使用的Regex功能是UDF,因为SQL Server没有本机Regex功能。所以我的回答只会有很多帮助,但可能会让你知道如何处理这个问题。

我想你可以在Oracle中构建一个正则表达式UDF,我们的正则表达式UDF返回一个结果集,我可以join或在SQL Server的情况cross/outer apply中它给了我{{ 1}}包含整个匹配,Value varchar包含捕获的子匹配:

SubMatches xml

使用表create table #A (data varchar(100)); Insert into #A values ('101,#abc-sds)dfgd)3453)#xyz-hju)dddjfj)eieei)2323'); Insert into #A values ('102,#abc-ddeff)errr)3434)#xyz-bnhb)hehe)333)#abc-dew)weerr)2343)#efg-3434)34'); declare @cols nvarchar(max), @q nvarchar(max) -- Gets found columns comma-separated in @cols: select @cols = isnull(@cols + ', ', '') + substring(r.Value, 2, len(r.Value)-2) from #A cross apply dbo.RegexFind(data, '#(\w+)-', 1, 1, 1) r group by r.Value -- Dynamically create #B with @cols and insert set @q = N'create table #B(id int, ' + replace(@cols, ', ', ' varchar(255), ') + ' varchar(255)) insert into #B select p.* from ( select r.Value, a.SubMatches.value(''(//submatch[@index=0]/@value)[1]'', ''varchar(255)'') col, a.SubMatches.value(''(//submatch[@index=1]/@value)[1]'', ''varchar(255)'') val from #A -- Find the ID at the start cross apply dbo.RegexFind(data, ''^\d+'', 1, 1, 1) r -- Find any and all #___- occurrences and the text after it outer apply dbo.RegexFind(data, ''#(\w+)-([^#]+)'', 1, 1, 1) a ) s pivot ( -- Pivot dynamically on the found @cols min(val) for col in (' + @cols + ') ) p select * from #B' exec sp_executesql @q 的示例内容,这将提供以下SQL(#A的内容):

@q

请注意,此create table #B(id int, abc varchar(255), efg varchar(255), xyz varchar(255)) insert into #B select p.* from ( select r.Value, a.SubMatches.value('(//submatch[@index=0]/@value)[1]', 'varchar(255)') col, a.SubMatches.value('(//submatch[@index=1]/@value)[1]', 'varchar(255)') val from #A -- Find the ID at the start cross apply dbo.RegexFind(data, '^\d+', 1, 1, 1) r -- Find any and all #___- occurrences and the text after it outer apply dbo.RegexFind(data, '#(\w+)-([^#]+)', 1, 1, 1) a ) s pivot ( -- Pivot dynamically on the found @cols min(val) for col in (abc, efg, xyz) ) p select * from #B 临时表仅存在于动态SQL中,但我不知道Oracle如何处理此问题。