【问题标题】:Is it possible to perform multiple replacements in one function call?是否可以在一个函数调用中执行多个替换?
【发布时间】:2020-03-18 16:28:29
【问题描述】:

如果你想一次性替换多个字符串,当然可以嵌套 REPLACE 函数,例如。像这样:

SELECT REPLACE(REPLACE(REPLACE(foo, 'apple', 'fruit'), 'banana', 'fruit'), 'lettuce', 'vegetable')
FROM bar

如果您必须进行大量替换,您的代码将变得丑陋且难以阅读。有没有多替换功能之类的东西?哪个可能需要 2 个数组作为参数?可以肯定的是,我对 TRANSLATE 函数很熟悉,但正如我的示例所示,我想替换整个单词,而不仅仅是单个字符。

【问题讨论】:

  • 您可以使用递归 CTE 来做到这一点。
  • 可能使用正则表达式 - 但我怀疑它会更快。有时,通过转换为 xml 并在其上使用 xml 扩展,数据会很容易处理——这可能会奏效。
  • 您在寻找性能还是“干净”?为了表现,做你正在做的事情。为了清洁,创建一个函数来做你想做的事情并使用它。

标签: sql postgresql replace


【解决方案1】:

我在寻找清洁度,而不是性能,所以我接受了你的建议 404。

这是我写的函数:

CREATE OR REPLACE FUNCTION multi_replace(  
                                        _string                 TEXT,
                                        VARIADIC _param_args    TEXT[]
                                        )                                     
RETURNS TEXT AS    
$BODY$    
    DECLARE
            _old        RECORD;
            _new        TEXT;    
    BEGIN
        FOR _old in     (
                        SELECT 
                            _param_args[i]                      AS tekst, 
                            i                                   AS indexnummer
                        FROM  generate_series(1, 5, 2) i
                        )                           
                        LOOP 
                            _new    := COALESCE(_param_args[_old.indexnummer+1], '');
                            _string := REPLACE(_string, _old.tekst, _new);
                        END LOOP;    
        RETURN _string;            
    END;         
$BODY$
  LANGUAGE plpgsql VOLATILE

这是一个示例调用:

select multi_replace('I love to drink milk in the morning', 'milk', 'beer', 'morning', 'evening', 'I', 'we');

奇怪这不是一个标准功能,也许是下一个版本的好主意?谢谢大家的建议!

【讨论】:

  • 您不需要generate_series()。您可以通过输入数组直接loop 或使用unnest(..) with ordinality
  • 很有趣,谢谢。我将如何处理确定要替换哪些元素以及哪些是替换值?
  • @horse 很不错,今天学到了一些东西!如果我知道怎么做,我想让你的评论成为公认的答案。
【解决方案2】:

我会通过以下方式实现这样的功能:

CREATE OR REPLACE FUNCTION multi_replace(_string text, variadic _param_args text[])                                     
  RETURNS TEXT 
AS    
$BODY$    
DECLARE
  _index integer;
BEGIN
  FOR _index IN 1 .. cardinality(_param_args) - 1 by 2 loop
    _string := replace(_string, _param_args[_index], _param_args[_index+1]);
  end loop;
  RETURN _string;            
END;         
$BODY$
LANGUAGE plpgsql VOLATILE;

cardinality() 返回参数数组的长度,by 2 在每次迭代时将循环索引增加 2,以便在循环内使用 _index_index + 1 访问属于一起的对是安全的.

在线示例:https://rextester.com/LITG61720

【讨论】:

  • 但是当替换字符串与后面的搜索词匹配时,它不会按预期工作。示例:multi_replace('I love bar and baz', 'bar', 'bazinga', 'baz', 'music') 将生成 I love musicinga and music 而不是预期的 I love bazinga and music
  • 这实际上是 Daniel 的预期行为,考虑到该函数应该与多个(嵌套)替换函数(如我的问题中所述)执行相同的操作。如果您需要一个执行单数顺序替换的函数,我建议您提出一个新问题(并可能链接到这个问题以节省大家的时间)。
  • 我刚刚在查看此函数时(再次)意识到波动率可能应该设置为“不可变”,而不是“易失”。不知道它是否会对性能产生很大影响,但我想它也不会受到伤害(如果我错了,请纠正我)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
  • 2018-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多