2008-09-17 10 views
9

Mam ciąg znaków pochodzący z tabeli, np. "Nie mogę zapłacić {1}, jako płatność {2} z powodu {3}". Chcę zastąpić {1} pewną wartością, {2} pewną wartością i {3} pewną wartością.jak zastąpić wiele ciągów razem w Oracle

Czy można zastąpić wszystkie 3 w jednej funkcji wymiany? lub czy istnieje sposób, aby bezpośrednio napisać zapytanie i uzyskać wartość zastępowaną? Chcę zastąpić te ciągi w procedurze przechowywanej Oracle oryginalny ciąg pochodzi z jednej z moich tabel Właśnie robię zaznacz na tej tabeli

, a następnie chcę zastąpić wartości {1}, {2}, {3} z tego łańcucha do innej wartości, które mam z innej tabeli

+0

Możliwy duplikat [Multiple REPLACE funkcja w Oracle] (https://stackoverflow.com/questions/2947623/multiple-replace-function-in-oracle) – Joaquinglezsantos

Odpowiedz

12

Chociaż nie jest to jeden telefon, można zagnieździć replace() rozmowy:

SET mycol = replace(replace(mycol, '{1}', 'myoneval'), '{2}', mytwoval) 
+0

Czy drugie mytwoval brakuje pojedynczych cudzysłowów? –

+0

@SimonTheCat Masz rację! (O ile mytwoval nie był zmienną) – hamishmcn

-1

Jeśli robisz to wnętrze select, można po prostu ułóż je razem, jeśli wartości zastępcze są kolumnami, używając łączenia ciągów.

4

Jeśli istnieje wiele zmiennych do zastąpienia i masz je w innej tabeli i jeśli liczba zmiennych jest zmienna, możesz użyć rekurencyjnego CTE, aby je zastąpić. Przykład poniżej. W tabeli fg_rulez wstawiasz struny wraz z ich wymianą. W tabeli fg_data masz swoje ciągi wejściowe.

set define off; 
drop table fg_rulez 
create table fg_rulez as 
    select 1 id,'<' symbol, 'less than' text from dual 
    union all select 2, '>', 'great than' from dual 
    union all select 3, '$', 'dollars' from dual 
    union all select 4, '&', 'and' from dual; 
drop table fg_data; 
create table fg_Data AS(
    SELECT 'amount $ must be < 1 & > 2' str FROM dual 
    union all 
    SELECT 'John is > Peter & has many $' str FROM dual 
    union all 
    SELECT 'Eliana is < mary & do not has many $' str FROM dual 

    ); 


WITH q(str, id) as (
    SELECT str, 0 id 
    FROM fg_Data 
    UNION ALL 
    SELECT replace(q.str,symbol,text), fg_rulez.id 
    FROM q 
    JOIN fg_rulez 
    ON q.id = fg_rulez.id - 1 
) 
SELECT str from q where id = (select max(id) from fg_rulez); 

Tak, pojedynczy replace.

Wynik:

amount dollars must be less than 1 and great than 2 
John is great than Peter and has many dollars 
Eliana is less than mary and do not has many dollars 

Symbol terminologia zamiast zmiennej pochodzi z this duplicated question.

Oracle 11gR2

+0

Aliasing w klauzuli WITH jest obsługiwany od Oracle 11gR2. – Stephan

+1

IMH jest to doskonała odpowiedź, ponieważ odnosi się do punktu, który był niestety nieskomplikowany w odniesieniu do pytania, a mianowicie do umożliwienia aktualizacji zastąpionych terminów bez edytowania faktycznego zapytania (co jest przydatnym scenariuszem w kontrolowanym środowisku). – Neil

1

Jeśli liczba wartości, które zastępują jest zbyt duże lub trzeba umieć aby go łatwo utrzymać, możesz również podzielić ciąg znaków, użyć tabeli słowników i ostatecznie zebrać wyniki.

W przykładzie poniżej jestem przy założeniu, że słowa w swoim struny są oddzielone blankspaces i WordCount w ciągu nie będzie większy niż 100 (pivot tabeli liczności)

with Dict as 
(select '{1}' String, 'myfirstval' Repl from dual 
    union all 
    select '{2}' String, 'mysecondval' Repl from dual 
    union all 
    select '{3}' String, 'mythirdval' Repl from dual 
    union all 
    select '{Nth}' String, 'myNthval' Repl from dual 

) 
,MyStrings as 
(select 'This is the first example {1} ' Str, 1 strnum from dual 
    union all 
    select 'In the Second example all values are shown {1} {2} {3} {Nth} ', 2 from dual 
    union all 
    select '{3} Is the value for the third', 3 from dual 
    union all 
    select '{Nth} Is the value for the Nth', 4 from dual 
) 
,pivot as (
    Select Rownum Pnum 
    From dual 
    Connect By Rownum <= 100 
) 
,StrtoRow as 
(
SELECT rownum rn 
     ,ms.strnum 
     ,REGEXP_SUBSTR (Str,'[^ ]+',1,pv.pnum) TXT 
    FROM MyStrings ms 
     ,pivot pv 
where REGEXP_SUBSTR (Str,'[^ ]+',1,pv.pnum) is not null 
) 
Select Listagg(NVL(Repl,TXT),' ') within group (order by rn) 
from 
(
Select sr.TXT, d.Repl, sr.strnum, sr.rn 
    from StrtoRow sr 
     ,dict d 
where sr.TXT = d.String(+) 
order by strnum, rn 
) group by strnum 
+0

To świetne wykorzystanie klauzuli WITH i kudos do implementacji rozwiązania SQL-only, ale wynik jest nadal dość trudny (dla niektórych z nas) do parsowania! Wygląda na to, że działa dobrze, ale jeśli zaimplementowałem w moim kodzie, nie poprosiłbym współpracownika o sprawdzenie poprawności. Zastrzelą mnie! :-) – StewS2