2017-10-18 11 views
2

PL/SQL 블록 (루프, 사용자 정의 함수/저장 프로 시저, 함수 구조 ...)을 사용하지 않고 특정 문자열을 다른 문자열과 위치로 대체 할 수 있는지 궁금합니다. 여기문자열을 다른 문자열과 각각의 위치에 더하기로 바꾸십시오.

: st ->pos_num

입력 :

"aa bbb st cccc dddd st eeeeeeeeeee ffff g st g h i st j k l m st" 

출력 :

"aa bbb pos_1 cccc dddd pos_2 eeeeeeeeeee ffff g pos_3 g h i pos_4 j k l m pos_5" 

DBFiddle

제가 그것 WI를 달성 할 수 있다고 생각 번째 라인 작업 (어쩌면 정규식).

+1

예. 'REGEXP_INSTR','REGEXP_REPLACE' 및'LEVEL' 조합이있을 수 있습니다. –

+0

은 재귀 cte ok입니까? 또는 당신은 오직 하나의 라이너 선호 :)? –

+0

@ VamsiPrabhala 솔루션을 게시하는 것이 좋습니다 :) 한 줄의 우아한 솔루션이 선호 되나 반드시 필요하지는 않습니다 :) – lad2025

답변

0

MODEL 절을 사용하여 :

select m_1 
from dual 
model dimension by (0 as key) 
measures (cast('st post aa bbb st cccc dddd st ee ffff g st g h i st j k l m st' 
       as varchar2(500)) as m_1) 
rules iterate (100) until(not regexp_like(m_1[0], '(|^)(st)(|$)')) 
(m_1[0] = regexp_replace(m_1[0], 
      '(|^)st(|$)','\1pos_'||to_char(ITERATION_NUMBER+1)||'\2',1,1)); 

DBFiddle Demo

출력 :

pos_1 post aa bbb pos_2 cccc dddd pos_3 ee ffff g pos_4 g h i pos_5 j k l m pos_6 
+0

성능에 관심이 있다면,이 두 가지 방법을 시도해보십시오.'model' 절은 아주 느립니다. 하지만 (1) 아마도 많은 양의 데이터가 없기 때문에 걱정하지 않아도됩니다. (2) 어떤 경우 든 확실하게 알 수있는 유일한 방법은 다른 사람이 아닌 ** 데이터를 테스트하는 것입니다. – mathguy

2

재귀 cte 접근.

with cte(string,col,cnt,repl) as 
(select string,1,regexp_count(string,'st'),regexp_replace(string,'st','pos_'||to_char(1),1,1) as repl 
from test 
union all 
select string,col+1,cnt,regexp_replace(repl,'st','pos_'||to_char(col+1),1,1) as repl 
from cte 
--join it to the original table if there are multiple rows, on string column. 
where col<cnt 
) 
cycle col set cycle to 1 default 0 
select string,repl 
from cte 
where cnt=col 
+0

+1 해결책은 근본적으로 정확합니다. 순환 CTE는 순환 위반으로 이어지며 순환 위반 CTE에 CYCLE 절을 추가하여 해결할 수 있습니다. 또한 재귀를 차단하기 위해 "count"를 사용할 필요가 없습니다. 내 답변에서 그렇게하는 한 가지 방법을 보여줍니다. 그러나 전반적으로 해결책은 좋습니다. 나는 CYCLE 절을 추가하기위한 답을 편집 할 것이다. – mathguy

1

다음은 재귀 CTE를 사용하는 약간 다른 해결책입니다. 공백 (또는 문자열의 시작 또는 끝)으로 둘러싸인 경우에만 st을 찾습니다.

with 
    inputs (str) as (
    select 'aa bbb st sccc dddd st eee fff g st g h i st j k l m st' from dual 
    union all 
    select 'st abc st st st where st is not st'      from dual 
    union all 
    select 'post st stop postal'          from dual 
), 
    r (lvl, str, new_str) as (
    select 1, str, str 
     from inputs 
    union all 
    select lvl + 1, str, 
      regexp_replace(new_str, '(|^)st(|$)', '\1pos_' || lvl || '\2', 1, 1) 
     from r 
     where regexp_like(new_str, '(|^)(st)(|$)') 
) 
select str, new_str 
from r 
where not regexp_like(new_str, '(|^)(st)(|$)') 
; 

STR              NEW_STR 
------------------------------------------------------- ---------------------------------------------------------------------- 
post st stop postal          post pos_1 stop postal 
aa bbb st sccc dddd st eee fff g st g h i st j k l m st aa bbb pos_1 sccc dddd pos_2 eee fff g pos_3 g h i pos_4 j k l m pos_5 
st abc st st st where st is not st      pos_1 abc pos_2 pos_3 pos_4 where pos_5 is not pos_6 
+0

입력 해 주셔서 감사합니다. 'MODEL'과 결합하면 매우 잘 작동합니다. – lad2025