我有2个表A
和B
。表A
中的数据包含一个字符串,我希望根据"#___-"
(abc
,xyz
,efg
等将其拆分为不同的列并将其复制进入表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
我尝试了正则表达式,但由于字符串大小可能会有所不同,并且由于重复发生,我无法进一步提供任何帮助。
答案 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如何处理此问题。