Как многократно использовать функцию REPLACE?

Использую функцию REPLACE для замены значений в строке, например:

SELECT REPLACE('THE NEW VALUE IS #VAL1#','#VAL1#','55') from dual;

Это нормально для замены одного значения.

А что, если 20+ значений, надо ли использовать 20+ функций REPLACE?
Или есть более практичное решение?



Свободный перевод вопроса Multiple REPLACE function от участника @Аdnan


Ответы (4 шт):

Автор решения: 0xdb

Возможно заменить вложенные вызовы REPLACE() регулярным выражением. Это намного быстрее, чем вложенные REPLACE(), и намного проще и понятней.

Чтобы заменить строки 'a','b','c' на 'd' в символьном столбце из заданной таблицы, выполните следующие действия:

select regexp_replace(string_col, 'a|b|c', 'd') from given_table

Это не что иное, как регулярное выражение для нескольких статических шаблонов с оператором or.

Будьте осторожны со специальными символами в регулярном выражении!


Свободный перевод ответа от участника @user3270011

→ Ссылка
Автор решения: 0xdb

Не всегда так просто получится заменить вложенные вызовы 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.

→ Ссылка
Автор решения: jashka34

Можно сделать свою функцию, которая будет искать и заменять.

Запрос будет вида:

SELECT MY_PKG.MY_REPLACE(...) from dual;

А внутри функции спрятать все эти 20 реплейсов.

Правда, если нужно в будет в функцию передавать 20 параметров, то тоже не очень красиво. Но хотя бы в самом запросе будет:

MY_PKG.MY_REPLACE(..20 параметров..)

, а не:

REPLACE(REPLACE(REPLACE(..20 раз..)))

, что по-моему немного лучше.

А если замены жёстко заданы и их передавать в функцию не нужно, то будет совсем хорошо.

→ Ссылка
Автор решения: Artem Boiko

Для себя создал вот такую функцию:

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$;

С ее помощью можно одним вызовом сделать несколько разных замен. В первом параметре - строка, в которой делаются замены. Во втором - заменяемые строки через запятую. В третьем - заменяющие строки через запятую. Если в заменах присутствует запятая можно в четвертом параметре задать другой разделитель.

→ Ссылка