Sql 将CLOB字段拆分为类似表的结构
我在类型为CLOB的Oracle数据库中有一个字段。我想把这个字段分成几列和几行。以下是内容示例:Sql 将CLOB字段拆分为类似表的结构,sql,oracle10g,Sql,Oracle10g,我在类型为CLOB的Oracle数据库中有一个字段。我想把这个字段分成几列和几行。以下是内容示例: 4:true5:false24:<p>option sample 1.</p>4:true22:<p>option sample 2.</p>5:false23:<p>option sample 3.</p>5:false22:<p>option sample 4.</p>5:false 结果应该如
4:true5:false24:<p>option sample 1.</p>4:true22:<p>option sample 2.</p>5:false23:<p>option sample 3.</p>5:false22:<p>option sample 4.</p>5:false
结果应该如下所示:
ID LEVEL ANSWER_OPTION VALUE
1 3 option sample 3 false
1 4 option sample 4 false
2 3 option sample 3 false
4 3 option sample 3 true
3 2 option sample 2 false
1 2 option sample 2 true
2 1 option sample 1 true
2 4 option sample 4 false
4 1 option sample 1 false
2 2 option sample 2 false
4 2 option sample 2 false
1 1 option sample 1 false
3 4 option sample 4 false
4 4 option sample 4 false
3 3 option sample 3 false
3 1 option sample 1 true
我们做出了以下声明,从而产生了上述结果
with guest_string as
( select qsn.id id
, dbms_lob.substr( qsn.guest, 2000, 1 ) answer_options
from mneme_question qsn
where qsn.id < 10
)
select distinct id
, level
, substr(regexp_substr( answer_options'<p>[^<]+', 1, level, 'i'), 4) ANSWER_OPTION
, substr(regexp_substr( answer_options, '(true|false)', regexp_instr( answer_options, '</p>', 1, 1), level, 'i'), 1) VALUE
from guest_string
connect by regexp_substr( answer_options, '<p>[^<]+', 1, level, 'i') is not null
这段代码的问题是分割我们所有的记录需要很长时间。我们必须在10排时切断它,5排需要0.25秒,10排需要16秒,15排大约需要2,5分钟。我们目前有30000行,它们将增长。目前,我们无法通过更改软件来更改数据模型,因此我们必须临时执行此操作
我们当前的方法是创建一个将为每个记录调用的过程,但是最好有一个更快的解析。有没有人建议如何创建一个脚本,可以在合理的时间内做到这一点。我们可以在夜间进行,但最好不要超过2分钟
顺便说一句,未来我们可以建立某种机制来确定哪些记录已经被解析,但这也需要某种形式的检测同时发生变化的已解析字段。我们还没有时间做这件事,所以现在我们需要尽可能快地进行粗略的解析
谢谢这里有一个不同的方法 代码可能没有它所能做到的那么好,您可能需要修复一些小问题。。。 我在11g上检查了它,找不到10g,并将您的输入用作我的clob列中的值。 对于10行,所有行的输入都与您给出的示例相同, 原始查询:9.8秒 新查询:0.08秒 我使用了一个流水线函数,下面是代码:
create or replace type t_parse is object(idd number, levell number, answer_option varchar2(128), valuee varchar2(4000));
/
create or replace type tab_parse is table of t_parse;
/
create or replace function split_answers return tab_parse
pipelined is
cursor c is
select * from mneme_question;
str_t clob;
phraseP varchar2(128);
phraseV varchar2(8);
i1s number;
i1e number;
i2s number;
levell number;
begin
for r in c loop
str_t := r.guest;
levell := 1;
while str_t is not null loop
i1s := dbms_lob.instr(str_t, '<p>', 1, 1) + 3;
if i1s = 3 then
str_t := '';
else
i1e := dbms_lob.instr(str_t, '</p>', 1, 1);
phraseP := dbms_lob.substr(str_t, i1e - i1s, i1s);
str_t := dbms_lob.substr(str_t, offset => i1e + 4);
i2s := dbms_lob.instr(str_t, 'true', 1, 1) ;
if i2s = 0 then
i2s := dbms_lob.instr(str_t, 'false', 1, 1) ;
if i2s = 0 then
str_t := '';
else
phraseV := dbms_lob.substr(str_t, 5, i2s);
pipe row(t_parse(r.id, levell, phraseP, phraseV));
levell := levell + 1;
end if;
else
phraseV := dbms_lob.substr(str_t, 4, i2s);
pipe row(t_parse(r.id, levell, phraseP, phraseV));
levell := levell + 1;
end if;
end if;
end loop;
end loop;
return;
end split_answers;
/
这里有一种不同的方法 代码可能没有它所能做到的那么好,您可能需要修复一些小问题。。。 我在11g上检查了它,找不到10g,并将您的输入用作我的clob列中的值。 对于10行,所有行的输入都与您给出的示例相同, 原始查询:9.8秒 新查询:0.08秒 我使用了一个流水线函数,下面是代码:
create or replace type t_parse is object(idd number, levell number, answer_option varchar2(128), valuee varchar2(4000));
/
create or replace type tab_parse is table of t_parse;
/
create or replace function split_answers return tab_parse
pipelined is
cursor c is
select * from mneme_question;
str_t clob;
phraseP varchar2(128);
phraseV varchar2(8);
i1s number;
i1e number;
i2s number;
levell number;
begin
for r in c loop
str_t := r.guest;
levell := 1;
while str_t is not null loop
i1s := dbms_lob.instr(str_t, '<p>', 1, 1) + 3;
if i1s = 3 then
str_t := '';
else
i1e := dbms_lob.instr(str_t, '</p>', 1, 1);
phraseP := dbms_lob.substr(str_t, i1e - i1s, i1s);
str_t := dbms_lob.substr(str_t, offset => i1e + 4);
i2s := dbms_lob.instr(str_t, 'true', 1, 1) ;
if i2s = 0 then
i2s := dbms_lob.instr(str_t, 'false', 1, 1) ;
if i2s = 0 then
str_t := '';
else
phraseV := dbms_lob.substr(str_t, 5, i2s);
pipe row(t_parse(r.id, levell, phraseP, phraseV));
levell := levell + 1;
end if;
else
phraseV := dbms_lob.substr(str_t, 4, i2s);
pipe row(t_parse(r.id, levell, phraseP, phraseV));
levell := levell + 1;
end if;
end if;
end loop;
end loop;
return;
end split_answers;
/
返回流水线表时有一些函数:
CREATE OR REPLACE FUNCTION split_clob(p_clob IN CLOB DEFAULT NULL,
p_varchar IN VARCHAR2 DEFAULT NULL,
p_separator IN VARCHAR2)
RETURN varchar_set
PIPELINED IS
l_clob CLOB;
BEGIN
l_clob := nvl(p_clob,
to_clob(p_varchar));
FOR rec IN (
WITH vals AS
(SELECT CAST(TRIM(regexp_substr(l_clob,
'[^'||p_separator||']+',
1,
levels.column_value)) AS
VARCHAR2(320)) AS val
FROM TABLE(CAST(MULTISET
(SELECT LEVEL
FROM dual
CONNECT BY LEVEL <=
length(regexp_replace(l_clob,
'[^'||p_separator||']+')) + 1) AS
sys.odcinumberlist)) levels)
SELECT val FROM vals)
LOOP
PIPE ROW(rec.val);
END LOOP;
RETURN;
END;
-还是和瓦查尔一起
SELECT * FROM TABLE(split_clob(p_varchar => '1,2,3,4,5,6, 7, 8, 9', p_separator => ','))
返回流水线表时有一些函数:
CREATE OR REPLACE FUNCTION split_clob(p_clob IN CLOB DEFAULT NULL,
p_varchar IN VARCHAR2 DEFAULT NULL,
p_separator IN VARCHAR2)
RETURN varchar_set
PIPELINED IS
l_clob CLOB;
BEGIN
l_clob := nvl(p_clob,
to_clob(p_varchar));
FOR rec IN (
WITH vals AS
(SELECT CAST(TRIM(regexp_substr(l_clob,
'[^'||p_separator||']+',
1,
levels.column_value)) AS
VARCHAR2(320)) AS val
FROM TABLE(CAST(MULTISET
(SELECT LEVEL
FROM dual
CONNECT BY LEVEL <=
length(regexp_replace(l_clob,
'[^'||p_separator||']+')) + 1) AS
sys.odcinumberlist)) levels)
SELECT val FROM vals)
LOOP
PIPE ROW(rec.val);
END LOOP;
RETURN;
END;
-还是和瓦查尔一起
SELECT * FROM TABLE(split_clob(p_varchar => '1,2,3,4,5,6, 7, 8, 9', p_separator => ','))
感谢您提供了另一种解决方案。我们在调用程序的模式方面正在取得进展。我们也将尝试您的解决方案。我们还提出了代码的改进版本。这是改进版本:使用rn作为select rownum rn from dual connect by rownum<10 select substrengexp_substrqsn.guest,“[^ok@BetaUser,以下是我的结果:对于一个包含clob列和20条记录的表,所有记录的值都与我从您的帖子中得到的值相同:原始qry:342.219;您的新qry:0.375;我的qry:0.11,但有一件奇怪的事-原始查询和我的查询返回了80条记录,但您的新查询返回了380Ok,非常感谢您的帮助。性能已经上升了。我想我们会从这里开始管理。我会将您的帖子标记为答案。感谢您提供了一个替代解决方案。我们正在调用过程的模式上取得进展。我们也会尝试您的解决方案。我们还提出了代码的改进版本。这是改进版本:使用rn作为select rownum rn frownum<10选择substrregexp_substrqsn.guest,“[^ok@BetaUser,以下是我的结果:对于一个包含clob列和20条记录的表,所有记录的值都与我从您的帖子中得到的值相同:原始qry:342.219;您的新qry:0.375;我的qry:0.11,但有一件奇怪的事-原始查询和我的查询返回了80条记录,但您的新查询返回了380Ok,非常感谢您的帮助。性能已经上升了。我想我们会从这里开始。我会把你的帖子标记为答案。谢谢