Oracle SQL:带有 REGEXP_SUBSTR 表达式的插入查询很长(拆分字符串)
Posted
技术标签:
【中文标题】Oracle SQL:带有 REGEXP_SUBSTR 表达式的插入查询很长(拆分字符串)【英文标题】:Oracle SQL: the insert query with REGEXP_SUBSTR expression is very long ( split string ) 【发布时间】:2013-09-13 13:08:05 【问题描述】:我必须在表 2 字段中插入(首先是主键(关于文章),第二个是关于它们的大小(这些文章)。
在源环境中,我将表、主键(TK 文章)和大小串联到第二个字段中。但是,我必须在目标表中插入 TK 文章和几个大小的文章。 例如,
来源:
ART SIZE**
1 | 28/30
2 | 30/32
3 | Size 10/Size 12/Size 14/Size 14
目标:
ART Size
1 | 28
1 | 30
2 | 30
2 | 32
3 | Size 10
3 | Size 12
3 | Size 14
3 | Size 16
难点是要知道字段中包含多少个'/'?
我已经查询了
SELECT ART,
REGEXP_SUBSTR(SIZE,'[^/]+',1,level)
FROM TABLLE
CONNECT BY REGEXP_SUBSTR(SIZE,'[^/]+',1,level) IS NOT NULL;
选择事务在 46 秒内运行并显示结果。但是 TABLE 有 100 000 行,并且插入事务太长并且不起作用。
有人可以在这点上帮助我吗?
感谢和问候
【问题讨论】:
你的INSERT
在哪里?
我将插入到表中选择 ART, REGEXP_SUBSTR(SIZE,'[^/]+',1,level) FROM TABLLE CONNECT BY REGEXP_SUBSTR(SIZE,'[^/]+',1,级别)不为空;
我的意思是请您在您的问题中添加您的准确 INSERT
声明。另请提供有关“不起作用”的详细信息。
从技术上讲,它运行了 8 个小时,我已经在下降结束前停止了它
您发布的查询确实有INSERT
。您可以发布您实际用于插入目标表的那个吗?
【参考方案1】:
正则表达式的计算成本非常高。如果需要处理大量行,我个人会使用存储过程-流水线表函数:
-- table with 100000 rows
create table Tb_SplitStr(col1, col2) as
select level
, 'Size 10/Size 12/Size 14/Size 14/Size 15/Size 16/Size 17'
from dual
connect by level <= 100000
PL/SQL 包:
create or replace package Split_Pkg as
type T_StrList is table of varchar2(1000);
function Str_Split(
p_str in varchar2,
p_dlm in varchar2
) return T_StrList pipelined;
end;
create or replace package body Split_Pkg as
function Str_Split(
p_str in varchar2,
p_dlm in varchar2
) return T_StrList pipelined
is
l_src_str varchar2(1000) default p_str;
l_dlm_pos number;
begin
while l_src_str is not null
loop
l_dlm_pos := instr(l_src_str, p_dlm);
case
when l_dlm_pos = 0
then pipe row (l_src_str);
l_src_str := '';
else pipe row(substr(l_src_str, 1, l_dlm_pos - 1));
l_src_str := substr(l_src_str, l_dlm_pos + 1);
end case;
end loop;
return;
end;
end;
带有正则表达式函数的 SQL 查询:
with ocrs(ocr) as(
select level
from ( select max(regexp_count(col2, '[^/]+')) as mx
from tb_splitStr) t
connect by level <= t.mx
)
select count(regexp_substr(s.col2, '[^/]+', 1, o.ocr)) as res
from tb_splitStr s
cross join ocrs o
结果:
-- SQL with regexp
SQL> with ocrs(ocr) as(
2 select level
3 from ( select max(regexp_count(col2, '[^/]+')) as mx
4 from tb_splitStr) t
5 connect by level <= t.mx
6 )
7 select count(regexp_substr(s.col2, '[^/]+', 1, o.ocr)) as res
8 from tb_splitStr s
9 cross join ocrs o
10 ;
Res
------------------------------
700000
Executed in 4.093 seconds
SQL> /
Res
------------------------------
700000
Executed in 3.812 seconds
--Query with pipelined table function
SQL> select count(*)
2 from Tb_SplitStr s
3 cross join table(split_pkg.Str_Split(s.col2, '/'))
4 ;
COUNT(*)
----------
700000
Executed in 2.469 seconds
SQL> /
COUNT(*)
----------
700000
Executed in 2.406 seconds
【讨论】:
【参考方案2】:This blogpost of mine 展示了六种不同的技术来处理这个查询。
不同的是它处理日期,你需要处理字符串。您可以通过使用 "regexp_count(size,'/') + 1" 作为迭代停止器和选择列表中的 regexp_substr(size,'[^/]+',1,i) 来解决这个问题。
【讨论】:
我喜欢你的博客 Rob!我相信史蒂夫乔布斯使用了“简单是复杂的终极形式”(意译)这句话。看看这个youtube vid,不管你喜不喜欢苹果,它都很棒。 是的,在 15 分 30 秒左右,他提到了较短的“简单是终极的复杂”,这实际上是来自达芬奇的名言。我博客上的那句话没有提到史蒂夫乔布斯或达芬奇。这是一个解释:rwijk.blogspot.nl/2007/09/about-motto.html【参考方案3】:使用一些 XML 怎么样?
> set serveroutput on
> drop table test_tab
table TEST_TAB dropped.
> create table test_tab
(
art number,
siz varchar2(100)
)
table TEST_TAB created.
> insert into test_tab values (1, '28/30')
1 rows inserted.
> insert into test_tab values (2, '30/32')
1 rows inserted.
> insert into test_tab values (3, 'Size 10/Size 12/Size 14/Size 14')
1 rows inserted.
> commit
committed.
> drop table test_tab2
table TEST_TAB2 dropped.
> create table test_tab2 as
select * from test_tab where 1=0
table TEST_TAB2 created.
> insert into test_tab2 (art, siz)
select art, extractvalue(x.column_value, 'e')
from test_tab, xmltable ('e' passing xmlparse( content '<e>' || replace(siz, '/', '</e><e>') || '</e>')) x
8 rows inserted.
> commit
committed.
> select * from test_tab2
ART SIZ
---------- ----------------------------------------------------------------------------------------------------
1 28
1 30
2 30
2 32
3 Size 10
3 Size 12
3 Size 14
3 Size 14
8 rows selected
又是这样,但最初有 100,000 行,并显示了时间安排。插入 400,000 行只用了 2 分钟多一点:
> set serveroutput on
> set timing on
> drop table test_tab
table TEST_TAB dropped.
Elapsed: 00:00:00.055
> create table test_tab
(
art number,
siz varchar2(100)
)
table TEST_TAB created.
Elapsed: 00:00:00.059
> --insert into test_tab values (1, '28/30');
> --insert into test_tab values (2, '30/32');
> --insert into test_tab values (3, 'Size 10/Size 12/Size 14/Size 14');
> insert into test_tab (art, siz)
select level, 'Size 10/Size 12/Size 14/Size 16'
from dual
connect by level <= 100000
100,000 rows inserted.
Elapsed: 00:00:00.191
> commit
committed.
Elapsed: 00:00:00.079
> drop table test_tab2
table TEST_TAB2 dropped.
Elapsed: 00:00:00.081
> create table test_tab2 as
select * from test_tab where 1=0
table TEST_TAB2 created.
Elapsed: 00:00:00.076
> -- perform inserts. This will result in 400,000 rows inserted
> -- note inserts are done conventionally (timing is acceptable)
> insert into test_tab2 (art, siz)
select art, extractvalue(x.column_value, 'e')
from test_tab, xmltable ('e' passing xmlparse( content '<e>' || replace(siz, '/', '</e><e>') || '</e>')) x
400,000 rows inserted.
Elapsed: 00:02:17.046
> commit
committed.
Elapsed: 00:00:00.094
> -- show some data in target table
> select * from test_tab2
where art = 1
ART SIZ
---------- ----------------------------------------------------------------------------------------------------
1 Size 10
1 Size 12
1 Size 14
1 Size 16
Elapsed: 00:00:00.103
【讨论】:
以上是关于Oracle SQL:带有 REGEXP_SUBSTR 表达式的插入查询很长(拆分字符串)的主要内容,如果未能解决你的问题,请参考以下文章
oracle测试函数,包含带有sql developer的游标
带有 BULK COLLECT 的 Oracle PL/SQL 6504