Как многократно использовать функцию REPLACE?
Использую функцию REPLACE для замены значений в строке, например:
SELECT REPLACE('THE NEW VALUE IS #VAL1#','#VAL1#','55') from dual;
Это нормально для замены одного значения.
А что, если 20+ значений, надо ли использовать 20+ функций REPLACE?
Или есть более практичное решение?
Свободный перевод вопроса Multiple REPLACE function от участника @Аdnan
Ответы (4 шт):
Возможно заменить вложенные вызовы REPLACE() регулярным выражением. Это намного быстрее, чем вложенные REPLACE(), и намного проще и понятней.
Чтобы заменить строки 'a','b','c' на 'd' в символьном столбце из заданной таблицы, выполните следующие действия:
select regexp_replace(string_col, 'a|b|c', 'd') from given_table
Это не что иное, как регулярное выражение для нескольких статических шаблонов с оператором or.
Будьте осторожны со специальными символами в регулярном выражении!
Свободный перевод ответа от участника @user3270011
Не всегда так просто получится заменить вложенные вызовы REPLACE() регулярным выражением. Например, если требуется каждый токен заменить не одним единственным, а только ему соответствующим значением.
Конечно, вложенные вызовы будут работать:
select replace (replace (replace ('abc',
'a', 'd'),
'b', 'e'),
'c', 'f') result
from dual;
RESULT
--------
def
Но с увеличением числа и длины значений, код с вложенными вызовами будет выглядеть уже не так красиво и понятно.
Можно поместить значения поиска и замены в отдельную таблицу и воспользоваться небольшой вспомогательной функцией, которую можно объявить прямо в запросе:
create table params (id, key, val) as
select 1, 'a', 'd' from dual union all
select 2, 'b', 'e' from dual union all
select 3, 'c', 'f' from dual;
create or replace type kvarg is object (key varchar2 (32), val varchar2 (32))
/
create or replace type kvargs is table of kvarg
/
with
function replaceall (str varchar2, kv kvargs) return varchar2 is
ret varchar2 (32767) := str;
begin
for i in 1..kv.count loop
ret := replace (ret, kv(i).key, kv(i).val);
end loop;
return ret;
end;
param (args) as (
select cast (multiset (
select key, val
from params order by id) as kvargs)
from dual
)
select replaceall ('abc', args) result
from dual, param;
RESULT
--------
def
На db<>fiddle.
Можно сделать свою функцию, которая будет искать и заменять.
Запрос будет вида:
SELECT MY_PKG.MY_REPLACE(...) from dual;
А внутри функции спрятать все эти 20 реплейсов.
Правда, если нужно в будет в функцию передавать 20 параметров, то тоже не очень красиво. Но хотя бы в самом запросе будет:
MY_PKG.MY_REPLACE(..20 параметров..)
, а не:
REPLACE(REPLACE(REPLACE(..20 раз..)))
, что по-моему немного лучше.
А если замены жёстко заданы и их передавать в функцию не нужно, то будет совсем хорошо.
Для себя создал вот такую функцию:
CREATE OR REPLACE FUNCTION lib.replaces(
in_initial_string text,
in_remove_strings text,
in_insert_strings text,
in_separator text DEFAULT ','
) RETURNS text
LANGUAGE 'plpgsql'
IMMUTABLE
AS $BODY$
declare updated_string text;
declare remove_string text;
declare insert_string text;
declare i int;
begin
updated_string = in_initial_string;
i = 1;
loop
remove_string = trim(split_part(in_remove_strings, in_separator, i));
insert_string = trim(split_part(in_insert_strings, in_separator, i));
if remove_string <> '' and insert_string <> '' then
updated_string = replace(updated_string, remove_string, insert_string);
i = i + 1;
else
exit;
end if;
end loop;
return updated_string;
end;
$BODY$;
С ее помощью можно одним вызовом сделать несколько разных замен. В первом параметре - строка, в которой делаются замены. Во втором - заменяемые строки через запятую. В третьем - заменяющие строки через запятую. Если в заменах присутствует запятая можно в четвертом параметре задать другой разделитель.