Если вы хотите сделать это, не заменяя шаблон ?'
фиксированным фиктивным символом - будь то '#'
или что-то еще, что, как вы уверены, никогда не появится, - тогда вы можете использовать шаблон регулярного выражения, например так:
-- bind variable for sample value
var str varchar2(20);
exec :str := q'[aaa'dd?'d'xxx']';
select regexp_substr(:str, '((.*?[^?])*?)(''|$)', 1, level, null, 1) as result
from dual
connect by level < regexp_count(:str, '((.*?[^?])*?)(''|$)');
RESULT
--------------------
aaa
dd?'d
xxx
и затем вы можете просто применить простую замену:
select replace(
regexp_substr(:str, '((.*?[^?])*?)(''|$)', 1, level, null, 1),
'?''',
'''') as result
from dual
connect by level < regexp_count(:str, '((.*?[^?])*?)(''|$)');
RESULT
--------------------
aaa
dd'd
xxx
Если у вас есть два соседних неэкранированных разделителя, вы получаете нулевой элемент из этой позиции (этого не произошло)с более ранней версией шаблона регулярных выражений):
exec :str := q'[aaa''dd?'d'xxx']';
-- just to make them more visible...
set null (null)
select replace(
regexp_substr(:str, '((.*?[^?])*?)(''|$)', 1, level, null, 1),
'?''',
'''') as result
from dual
connect by level < regexp_count(:str, '((.*?[^?])*?)(''|$)');
RESULT
--------------------
aaa
(null)
dd'd
xxx