这是一个简化的选项,适用于源表中的单行;如果它必须为多个行工作,事情会变得更加复杂(不是说它不能完成,而是这段代码看起来会更更糟糕)。
此外,它假定每个“子字符串”(行)都可以转换为VARCHAR2(使用TO_CHAR)。
样本数据:
SQL> select * from test;
COL
--------------------------------------------------------------------------------
BlahBlah Blah;
TextAboutSomethingToFind.ExampleA;
ExtraText; MoreExtraText;EvenMoreExtraText;
LastExtraText;
TextAboutSomethingToFind.ExcibitB; TextAboutSomethingToFind.Pattern?;
EndText;
解决方案,我的方式。遵循代码中的 cmets。如果您不确定它的作用,请逐个 CTE 执行它并观察每个 SELECTs 返回的值。
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>