web-dev-qa-db-ja.com

Oracleの複数のREPLACE機能

OracleのREPLACE関数を使用して、次のような文字列の値を置き換えています。

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

したがって、これは1つの値を置き換えても問題ありませんが、20 +の場合、20 +のREPLACE関数を使用する必要がありますか、またはより実用的なソリューションがあります。

すべてのアイデアを歓迎します。

22
Adnan

このスレッドが古くてもGoogleで最初のものであるため、正規表現を使用して、ここで実装した関数と同等のOracleを投稿します。

入れ子になったreplace()よりもかなり速く、はるかにきれいです。

特定のテーブルの文字列列で文字列「a」、「b」、「c」を「d」に置き換えるには

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

これは、「or」演算子を使用したいくつかの静的パターンの正規表現に他なりません。

正規表現の特殊文字に注意してください!

41
user3270011

結果に留意してください

SELECT REPLACE(REPLACE('TEST123','123','456'),'45','89') FROM DUAL;

123を456に置き換え、45を89に置き換えることができることを見つけます。同等の結果を持つ関数の場合、優先順位を複製する必要があります(つまり、同じ順序で文字列を置き換える)。

同様に、文字列「ABCDEF」を取得し、「ABC」を「123」に、「CDE」を「xyz」に置き換えるように指示する場合も、「123EF」または「ABxyzF」のどちらであるかを判断するために優先順位を考慮する必要があります。

要するに、入れ子になったREPLACEよりも単純なジェネリックを思い付くのは難しいでしょう(ただし、sprintfスタイルの関数のようなものは便利な追加機能です)。

22
Gary Myers

Oracleで複数の文字列を一緒に置き換える方法 に対する受け入れられた答えは、ネストされたREPLACEステートメントの使用を示唆しており、より良い方法はないと思います。

これを多用する場合は、独自の関数を記述することを検討できます。

CREATE TYPE t_text IS TABLE OF VARCHAR2(256);

CREATE FUNCTION multiple_replace(
  in_text IN VARCHAR2, in_old IN t_text, in_new IN t_text
)
  RETURN VARCHAR2
AS
  v_result VARCHAR2(32767);
BEGIN
  IF( in_old.COUNT <> in_new.COUNT ) THEN
    RETURN in_text;
  END IF;
  v_result := in_text;
  FOR i IN 1 .. in_old.COUNT LOOP
    v_result := REPLACE( v_result, in_old(i), in_new(i) );
  END LOOP;
  RETURN v_result;
END;

そして、次のように使用します:

SELECT multiple_replace( 'This is #VAL1# with some #VAL2# to #VAL3#',
                         NEW t_text( '#VAL1#', '#VAL2#', '#VAL3#' ),
                         NEW t_text( 'text', 'tokens', 'replace' )
                       )
FROM dual

これは、置き換えるトークンを含むテキストです

すべてのトークンが同じ形式('#VAL' || i || '#')である場合、パラメーターin_oldを省略して、代わりにループカウンターを使用できます。

21
Peter Lang

これは古い投稿ですが、私は結局Peter Langの考えを使用し、同様の、しかしまだ異なるアプローチをしました。ここに私がやったことがあります:

CREATE OR REPLACE FUNCTION multi_replace(
                        pString IN VARCHAR2
                        ,pReplacePattern IN VARCHAR2
) RETURN VARCHAR2 IS
    iCount  INTEGER;
    vResult VARCHAR2(1000);
    vRule   VARCHAR2(100);
    vOldStr VARCHAR2(50);
    vNewStr VARCHAR2(50);
BEGIN
    iCount := 0;
    vResult := pString;
    LOOP
        iCount := iCount + 1;

        -- Step # 1: Pick out the replacement rules
        vRule := REGEXP_SUBSTR(pReplacePattern, '[^/]+', 1, iCount);

        -- Step # 2: Pick out the old and new string from the rule
        vOldStr := REGEXP_SUBSTR(vRule, '[^=]+', 1, 1);
        vNewStr := REGEXP_SUBSTR(vRule, '[^=]+', 1, 2);

        -- Step # 3: Do the replacement
        vResult := REPLACE(vResult, vOldStr, vNewStr);

        EXIT WHEN vRule IS NULL;
    END LOOP;

    RETURN vResult;
END multi_replace;

次に、私はこのようにそれを使用することができます:

SELECT  multi_replace(
                        'This is a test string with a #, a $ character, and finally a & character'
                        ,'#=%23/$=%24/&=%25'
        )
FROM dual

これにより、任意の文字/文字列で任意の文字/文字列を使用できるようになります。

私は自分のブログにこれに関する投稿を書きました。

4
TJ Abrahamsen

すべてのソース文字列と置換文字列が1文字の長さしかない場合、単にTRANSLATE関数を使用できます。

  SELECT translate('THIS IS UPPERCASE', 'THISUP', 'thisup') 
  FROM DUAL

詳細については、 Oracleドキュメント を参照してください。

4
Frank Schmitt

パラメーターとしてvarchar2のテーブルを使用して、一般的な複数置換文字列Oracle関数を作成しました。 varcharは、tableの位置rownum値に置き換えられます。

例えば:

Text: Hello {0}, this is a {2} for {1}
Parameters: TABLE('world','all','message')

戻り値:

Hello world, this is a message for all.

タイプを作成する必要があります。

CREATE OR REPLACE TYPE "TBL_VARCHAR2" IS TABLE OF VARCHAR2(250);

機能は次のとおりです。

CREATE OR REPLACE FUNCTION FN_REPLACETEXT(
    pText IN VARCHAR2, 
    pPar IN TBL_VARCHAR2
) RETURN VARCHAR2
IS
    vText VARCHAR2(32767);
    vPos INT;
    vValue VARCHAR2(250);

    CURSOR cuParameter(POS INT) IS
    SELECT VAL
        FROM
            (
            SELECT VAL, ROWNUM AS RN 
            FROM (
                  SELECT COLUMN_VALUE VAL
                  FROM TABLE(pPar)
                  )
            )
        WHERE RN=POS+1;
BEGIN
    vText := pText;
    FOR i IN 1..REGEXP_COUNT(pText, '[{][0-9]+[}]') LOOP
        vPos := TO_NUMBER(SUBSTR(REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i),2, LENGTH(REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i)) - 2));

        OPEN cuParameter(vPos);
        FETCH cuParameter INTO vValue;
        IF cuParameter%FOUND THEN
            vText := REPLACE(vText, REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i), vValue);
        END IF;
        CLOSE cuParameter;
    END LOOP;

    RETURN vText;

EXCEPTION
      WHEN OTHERS
      THEN
         RETURN pText;
END FN_REPLACETEXT;
/

使用法:

TEXT_RETURNED := FN_REPLACETEXT('Hello {0}, this is a {2} for {1}', TBL_VARCHAR2('world','all','message'));
2