2010-06-01 14 views
20

Estoy usando la función REPLACE en Oracle para reemplazar valores en mi cadena como;Función de SUSTITUCIÓN múltiple en Oracle

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

Así que esto es buena idea reemplazar un valor, pero ¿qué pasa con 20+, 20+ debería usar REPLACE función o hay una solución más práctica.

Todas las ideas son bienvenidas.

Respuesta

31

Aunque este hilo sea viejo es el primero en Google, entonces publicaré un equivalente de Oracle a la función implementada aquí, usando expresiones regulares.

Es bastante más rápido que el reemplazo anidado(), y mucho más limpio.

Para reemplazar cadenas 'a', 'b', 'c' 'D' en una columna de cadena de una tabla dada

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

No es otra cosa que una expresión regular para varios patrones estáticos con 'o' operador.

¡Tenga cuidado con los caracteres especiales de regexp!

+0

Esta solución simple es mucho mejor que escribir sus propias funciones haciendo lo que ya se ha implementado. – Tosz

+0

Acepto que esta es la mejor respuesta con respecto a la pregunta real que se hace – dangel

+0

¡Mucho mejor! ¡Muchas gracias! – GeorgiG

20

La respuesta aceptada a how to replace multiple strings together in Oracle sugiere utilizar declaraciones anidadas REPLACE, y no creo que haya una manera mejor.

Si se va a hacer un uso intensivo de esto, se podía considerar escribir su propia función:

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; 

y luego usarlo como esto:

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 

Este es el texto con algunos tokens para reemplazar

Si todos sus tokens tienen el mismo formato ('#VAL' || i || '#'), puede omitir el parámetro in_old y usar su contador de bucle en su lugar.

+0

Gracias Peter Lang – Adnan

+0

@Adnan: De nada, pero me hubiera esperado durante algún tiempo antes de aceptar mi respuesta - Puede haber otros mejores respuestas/por ahí :) –

+0

'RETURN VARCHAR2 DETERMINISTIC' podría ser probablemente más rápido. – Benoit

16

tener en cuenta las consecuencias

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

reemplazará al 123 con 456, a continuación, encontrará que puede sustituir a la 45 con 89. Por una función que tuvo un resultado equivalente, tendría que duplicar el precedencia (es decir, reemplazar las cadenas en el mismo orden).

Del mismo modo, tomar una cadena 'ABCDEF' y ordenarle que reemplace 'ABC' con '123' y 'CDE' con 'xyz' todavía tendría que dar cuenta de una precedencia para determinar si pasó a '123EF' o ABxyzF '.

En resumen, sería difícil encontrar algo genérico que sería más simple que un REEMPLAZO anidado (aunque algo que era más una función de estilo sprintf sería una adición útil).

3

Esta es una publicación anterior, pero terminé usando los pensamientos de Peter Lang e hice un enfoque similar pero diferente. Esto es lo que hice:

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; 

Entonces puede utilizar de esta manera:

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

Esto hace que sea posible para que yo pueda cualquier carácter/cadena con cualquier carácter/cadena.

Escribí una publicación sobre esto en mi blog.

4

En caso de que todas las cadenas de origen y de sustitución son sólo un carácter de longitud, puede simplemente usar la función TRANSLATE:

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

Ver the Oracle documentation para más detalles.

1

He creado una función de Oracle de cadena multi reemplaza general por una tabla de varchar2 como parámetro. El varchar será reemplazado por el valor de posición rownum de la tabla.

Por ejemplo:

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

Devuelve:

Hello world, this is a message for all. 

Debe crear un tipo:

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

La funcion es:

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; 
/

Uso:

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