Есть ли в Postgres / SQL способ заменить символы в строках из столбцов, где символы в строке являются именами столбцов? - PullRequest
1 голос
/ 26 марта 2020

У меня есть таблица с именем sentences, а таблица с именем logs.

Таблица sentences выглядит следующим образом:

|------------|---------------------------------------|
|     id     |                sentence               |
|------------|---------------------------------------|
|     1      |     [var1] says hello!                |
|------------|---------------------------------------|
|     2      |     [var1] says [var2]!               |
|------------|---------------------------------------|
|     3      |     [var1] says [var2] and [var3]!    |
|------------|---------------------------------------|
|     4      |     [var4] says [var2] to [var1]!     |
|------------|---------------------------------------|

Таблица logs выглядит например:

|------------|------------------|--------------|--------------|--------------|--------------|
|     id     |     sentenceId   |     var1     |     var2     |     var3     |     var4     |
|------------|------------------|--------------|--------------|--------------|--------------|
|     1      |         1        |     Sam      |              |              |              |
|------------|------------------|--------------|--------------|--------------|--------------|
|     2      |         2        |     Joe      |   what's up  |              |              |
|------------|------------------|--------------|--------------|--------------|--------------|
|     3      |         3        |     Tim      |     hey      | how are you  |              |
|------------|------------------|--------------|--------------|--------------|--------------|
|     4      |         4        |     Joe      |     hi       |              |    Tiffany   |
|------------|------------------|--------------|--------------|--------------|--------------|

Результат, который я пытаюсь получить:

|------------|-----------------------------------------|
|  logs.id   |            sentences.sentence           |
|------------|-----------------------------------------|
|     1      |   [Sam] says hello!                     |
|------------|-----------------------------------------|
|     2      |   [Joe] says [what's up]!               |
|------------|-----------------------------------------|
|     3      |   [Tim] says [hey] and [how are you]!   |
|------------|-----------------------------------------|
|     4      |   [Tiffany] says [hi] to [Joe]          |
|------------|-----------------------------------------|

Я не уверен, как написать запрос SQL, чтобы база данных выполняла текст замены для меня.

Я мог бы просто выбрать все из обеих таблиц, используя внутреннее соединение, а затем ввести код oop и выполнить подстановки самостоятельно. Т.е.:

SELECT logs.id, sentences.sentence, logs.var1, logs.var2, logs.var3, logs.var4 FROM logs INNER JOIN sentences ON logs.sentenceId = sentences.id

А затем в коде:

logs.forEach(log => log.sentence.replace(/\[(.*?)\]/g, ($matchedString, $columnName) => log[$columnName] ))

Но если возможно, я бы хотел, чтобы база данных сделала это для меня, чтобы мне не пришлось выбирать больше данные, чем мне нужно.

Ответы [ 2 ]

2 голосов
/ 26 марта 2020

Я бы написал для этого функцию:

create function replace_vars(p_sentence text, p_vars jsonb)
 returns text
as
$$
declare
  l_rec record;
  l_result text;
begin
  l_result := p_sentence;
  for l_rec in select * from jsonb_each_text(jsonb_strip_nulls(p_vars)) as x(var,value) 
  loop
     l_result := replace(l_result, l_rec.var, l_rec.value);
  end loop;
  return l_result;
end;
$$
language plpgsql;

Затем вы можете использовать ее следующим образом:

select s.id, s.sentence, replace_vars(s.sentence, to_jsonb(l)) new_sentence
from sentences s
  left join logs l on l.sentenceid = s.id;

Онлайн пример

0 голосов
/ 27 марта 2020

Элегантность всегда хороша, но иногда грубая сила делает это.

with logsnn (sentenceid, var1, var2, var3,var4) as
    ( select sentenceid 
           , coalesce(var1,'')  
           , coalesce(var2,'')  
           , coalesce(var3,'')  
           , coalesce(var4,'')
        from logs
    )  
select s.id
     ,(replace(replace(replace(replace(s.sentence 
        , '[var1]',l.var1)
        , '[var2]',l.var2)
        , '[var3]',l.var3)
        , '[var4]',l.var4)
      )  AS sentence
  from sentences s  
  left join logsnn l
        on l.sentenceid = s.id;

Если вам действительно нужны скобки для результата, измените параметры замены на

'[var1]','[' || l.var1 || ']')  

Ответ @JNevill близок к тому же, но я верю, что будет возвращено значение Null, если любое из var1, var2, var3 или var4 равно Null. CTE здесь заменяет Null пустой строкой. Postgres не считает пустую строку такой же, как ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...