'Apply all regexp_replaces from table sequentally to one string

I need to sequentially apply all regex_replace's from the table to one given string. How could I do that with one SQL request?

PostgreSQL is 11.2.

xbox=> \d presence_regex
           Table "public.presence_regex"
 Column  |  Type   | Collation | Nullable | Default
---------+---------+-----------+----------+---------
 match   | text    |           |          |
 replace | text    |           |          |

xbox=> select regexp_replace('Playing FIFA 19 Pro Clubs 2-1 LIL V BVB, 1st Half', 
                                match, replace) from presence_regex;

Select above performs replace to the original string and returns number of strings but I need the only one: the result after applying all the regex_replaces from the table.

Is it possible?



Solution 1:[1]

You need dynamic SQL for this. Meaning, you have to first build your SQL statement using data in table presence_regex, then execute it in the next step. You can wrap it up in a plpgsql function as single step.

Assuming

  • there is a column to indicate the order in which replacements shall be applied (which is meaningful).

  • you want to replace all occurrences, not just the first.

This function would achieve it:

CREATE OR REPLACE FUNCTION f_serial_regexp(_string text, OUT _result text) AS
$func$
BEGIN
   EXECUTE (
   SELECT 'SELECT '
       || string_agg('regexp_replace(', '')
       || '$1'
       || string_agg(format(', %L, %L, ''g'')', match, replace), '')
   FROM   (
      SELECT match, replace
      FROM   presence_regex
      ORDER  BY order_id    -- column indicating the order
      ) sub
   )
   USING $1
   INTO _result;
END
$func$  LANGUAGE plpgsql;

It builds and executes a SELECT query of the form (example for two rows in the table):

SELECT regexp_replace(regexp_replace($1, 'FIFA \d+', 'bab', 'g'), 'bab', 'XXX', 'g')

Remove the 4th parameter 'g' from regexp_replace() to only replace the first occurrence.

Call:

SELECT f_serial_regexp('Playing FIFA 19 Pro Clubs 2-1 LIL V BVB, 1st Half');

db<>fiddle here

Closely related, with more explanation:

Solution 2:[2]

based on Erwin Answer, a little bit of refactcoring. Since too much select a little bit of confusing. (for me personally)

create or replace function f_serial_regexp(_string text)
returns setof text language plpgsql as
$$
    begin
    RETURN QUERY 
    execute format('select regexp_replace($1 , match, replace, ''g'') '
    || 'from  presence_regex order by order_id')  using _string;
    end
$$;

obviously, pre-conditioin is the table presence_regex, column: match, replace must be there.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mark