Sql 将CLOB字段拆分为类似表的结构

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 结果应该如

我在类型为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 
结果应该如下所示:

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,非常感谢您的帮助。性能已经上升了。我想我们会从这里开始。我会把你的帖子标记为答案。谢谢