如何在Clob中找到一段文本并用所需的文本包装?

时间:2019-05-12 16:20:58

标签: oracle plsql

我有一个存储文本的表,我需要找到找到某些文本的所有位置,并在其前后添加文本 更具体地说,我需要更改“ SomethingToFind”模式发生的所有位置,找到它之前的空间(或行的开头)以及下一个“;”。并用文字包裹起来。

I.E。转换它-

TextAboutSomethingToFind.ExampleA;

进入此-

/* Caution
  TextAboutSomethingToFind.ExampleA;
Caution */

我有以下循环以所需的文字搜索所有记录。

for x in (select t.id
                     ,t.clobvalue
              from table_name t
            where REGEXP_like(t.clobvalue, 'SomethingToFind')
            )
loop
  --Some Operations
end loop;

clobvalue中的文本示例:

BlahBlah Blah;  
TextAboutSomethingToFind.ExampleA; 
ExtraText; MoreExtraText;EvenMoreExtraText;   
LastExtraText;  
TextAboutSomethingToFind.ExcibitB; TextAboutSomethingToFind.PatternС;  
EndText;  

所需结果:

 BlahBlah Blah;
/* Caution
TextAboutSomethingToFind.ExampleA; 
Caution */
ExtraText; MoreExtraText; EvenMoreExtraText;  
LastExtraText;  
/* Caution
TextAboutSomethingToFind.ExcibitB; 
Caution */ 
/* Caution
TextAboutSomethingToFind.PatternС;
Caution */
EndText;

我知道我某种程度上需要使用regexp_replace,但是我不知道如何正确执行此操作。我该怎么办?

1 个答案:

答案 0 :(得分:0)

这是一个简化的选项,可用于源表中的一行;如果必须为多个行工作,事情会变得更加复杂(不是无法完成,但此代码甚至会更糟糕),

此外,它假定每个“子字符串”(行)都可以转换为VARCHAR2(使用TO_CHAR)。

样本数据:

SQL> select * from test;

COL
--------------------------------------------------------------------------------
BlahBlah Blah;
TextAboutSomethingToFind.ExampleA;
ExtraText; MoreExtraText;EvenMoreExtraText;
LastExtraText;
TextAboutSomethingToFind.ExcibitB; TextAboutSomethingToFind.Pattern?;
EndText;

解决方案,写成我的方式。请遵循代码中的注释。如果不确定它的作用,请逐个CTE执行它,并观察每个SELECT返回的值。

SQL> with temp2 as
  2    -- split multi-lines column to rows, separated by CHR(10)
  3    (select level lvl2,
  4            to_char(regexp_substr(col, '[^' || chr(10) ||']+', 1, level, 'm')) col2
  5     from test
  6     connect by level <= regexp_count(col, chr(10)) + 1
  7    ),
  8  temp3 as
  9    -- out of all rows from the previous step, split those - that contain "SomethingToFind"
 10    -- more than once - into their own separate rows
 11    (select lvl2,
 12            level lvl3,
 13            trim(to_char(regexp_substr(col2, '[^;]+', 1, level))) col3
 14     from (select lvl2,
 15                  col2 from temp2
 16           where instr(col2, 'SomethingToFind') > 0
 17             and regexp_count(col2, ';') > 1
 18          )
 19     connect by level <= regexp_count(col2, ';')
 20    ),
 21  almost_there as
 22    -- apply the "Caution" clause to all "SomethingToFinds" from both cases
 23    (select lvl2,
 24            to_number(null) lvl3,
 25            case when instr(col2, 'SomethingToFind') > 0 then
 26                      '/* Caution' ||chr(10) || col2 || chr(10) || 'Caution */'
 27                 else col2
 28            end col
 29     from temp2
 30     where lvl2 not in (select lvl2 from temp3)
 31     union all
 32     select lvl2,
 33            lvl3,
 34            case when instr(col3, 'SomethingToFind') > 0 then
 35                      '/* Caution' ||chr(10) || col3 || chr(10) || 'Caution */'
 36                 else col3
 37            end col
 38     from temp3
 39    )
 40  -- Finally, put them together using LISTAGG, separated by CHR(10)
 41  select listagg(col, chr(10)) within group (order by lvl2, lvl3) result
 42  from almost_there;

RESULT
--------------------------------------------------------------------------------
BlahBlah Blah;
/* Caution
TextAboutSomethingToFind.ExampleA;
Caution */
ExtraText; MoreExtraText;EvenMoreExtraText;
LastExtraText;
/* Caution
TextAboutSomethingToFind.ExcibitB
Caution */
/* Caution
TextAboutSomethingToFind.Pattern?
Caution */
EndText;


SQL>