2017-10-18 12 views
2

Je me demande s'il est possible de remplacer une chaîne spécifique par une chaîne plus une position sans utiliser PL/SQL (boucles, fonctions définies par l'utilisateur/procédures stockées, avec construction de fonction ...).Remplacer la chaîne par une autre chaîne plus la position correspondante

ici: st ->pos_num

Entrée:

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

Sortie:

"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

Je pense qu'il est possible d'y parvenir wi l'opération d'une ligne (peut-être regex).

+1

Oui. peut être avec la combinaison 'REGEXP_INSTR',' REGEXP_REPLACE' et 'LEVEL'.? –

+0

est un cte récursif ok? ou vous préférez seulement un paquebot :)? –

+0

@VamsiPrabhala N'hésitez pas à poster votre solution :) Une ligne élégante solution est préférable, mais pas nécessaire :) – lad2025

Répondre

0

En utilisant MODEL clause:

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

Sortie:

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

Si vous êtes intéressé par la performance, vous pouvez toujours essayer les deux façons.La clause 'model' est notoirement lente; mais (1) peut-être que vous n'avez pas beaucoup de données, alors vous vous en fichez; et (2) dans tous les cas, le seul moyen de savoir avec certitude est de tester ** vos ** données, pas celles de quelqu'un d'autre. – mathguy

2

Une approche cte récursive.

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 La solution est essentiellement correcte. Le CTE récursif entraîne une violation de cycle, qui peut être résolue en ajoutant une clause CYCLE au CTE récursif. En outre, il n'est pas nécessaire d'utiliser le "compte" pour couper la récursivité; Je montre un moyen de le faire dans ma réponse. Mais globalement, la solution est bonne. Je vais modifier la réponse pour ajouter la clause CYCLE. – mathguy

1

Voici une solution légèrement différente utilisant CTE récursif. Il cherche st seulement quand il est entouré par des espaces (ou par le début ou la fin de la chaîne).

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

Merci pour votre contribution. Le combiner avec 'MODEL' fonctionne très bien :) – lad2025