Несколько строковых подстановок в PostgreSQL - PullRequest
2 голосов
/ 21 апреля 2020

У меня есть столбец с аббревиатурами, разделенными такими пробелами, как этот

'BG MSG'

Также есть еще одна таблица с подстановками

target  replacement
----------------------
'BG',  'Brick Galvan'
'MSG', 'Mosaic Galvan'

Цель состоит в том, чтобы применить все подстановки к аббревиатурам, чтобы получить что-то вроде

'Brick Galvan Mosaic Galvan' из 'BG MSG'

Я знаю, что мог бы сделать

replace( replace('BG MSG', 'BG', 'Brick Galvan'), 'MSG', 'Mosaic Galvan')

Но представьте, что есть сотни подстановок и они могут меняться от одного дня к другому. Результирующий запрос будет ужасно поддерживать.

Я имею в виду, я мог бы создать генератор кода, который будет создавать запрос со всеми вложенными заменами, но я ищу что-то более элегантное и postgres -нативное .

Я нашел такие решения Как заменить несколько специальных символов в Postgres 9.5 , но они, похоже, работают только для одиночных символов.

Ответы [ 2 ]

3 голосов
/ 22 апреля 2020

Допустим, ваши таблицы выглядят так:

create table my_table(id serial primary key, abbrevs text);
insert into my_table (abbrevs) values
('BG MSG');

create table substitutions(target text, replacement text);
insert into substitutions values
('BG',  'Brick Galvan'),
('MSG', 'Mosaic Galvan');

Вы можете получить каждую аббревиатуру в одной строке:

select id, unnest(string_to_array(abbrevs, ' ')) as abbrev
from my_table

 id | abbrev
----+--------
  1 | BG
  1 | MSG
(2 rows)

и использовать их, чтобы присоединиться к таблице substitution и получить полные имена:

select id, string_agg(replacement, ' ') as full_names
from (
    select id, unnest(string_to_array(abbrevs, ' ')) as abbrev
    from my_table
    ) t
join substitutions on abbrev = target
group by id

 id |         full_names
----+----------------------------
  1 | Brick Galvan Mosaic Galvan
(1 row) 

Db <> скрипка.

2 голосов
/ 22 апреля 2020

Подход с вложенной заменой будет работать, но он довольно уродлив, верно?

SELECT REPLACE(REPLACE(REPLACE(REPLACE(…

После тщательного форматирования, чтобы он выглядел читабельным, лучшее, что вы можете получить:

SELECT 
    REPLACE(
        REPLACE(
            REPLACE(
                REPLACE(...

С другой стороны, вы можете просто использовать решение LATERAL JOIN, которое использует больше символов, но оно определенно более читабельно.

-- Input: BG, MSG
-- Output: Brick Galvan, Mosaic Galvan
SELECT msg.Materials
FROM (SELECT 'BG, MSG' AS Materials) mt
         INNER JOIN LATERAL (SELECT REPLACE(mt.Materials::text, 'BG', 'Brick Galvan') AS Materials) bg ON true
         INNER JOIN LATERAL (SELECT REPLACE(bg.Materials::text, 'MSG', 'Mosaic Galvan') AS Materials) msg ON true;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...