我想替换字符串中第一次出现的多个值。请考虑以下示例:
输入字符串: a,a,a,b,b,c
要替换的值: a,b
预期输出: ,a,a,,b,c
使用|
运算符不起作用,如下所示:
select regexp_replace('a,a,a,b,b,c','a|b',null,1,1) from dual;
输出:,a,a,b,b,c
。这仅替换a
的第一次出现。
作为对此的扩展,如果要多次替换a
,那么第二次出现也应该在输入中替换:
输入字符串:a,a,a,b,b,c
要替换的值: a,b,a
预期输出: ,,a,,b,c
这可以通过REGEXP_REPLACE
或其他方式实现吗?如果有,怎么样?在此先感谢您的帮助!
答案 0 :(得分:0)
我猜可能是更好的解决方案。
我只能用递归SQL =( 查看下面的脚本:
$NF != ""
答案 1 :(得分:0)
这是完全通用性的一种方法。如果我正确理解了问题,给定逗号分隔的字符串,请替换稍后在字符串中使用NULL
重复的每个符号(标记) - 但保留所有逗号作为占位符。该解决方案涵盖了原始字符串已经具有NULL
的占位符的情况(即,连续逗号之间没有标记的连续逗号)。在极端情况下,原始字符串也可能为空(与Oracle中的NULL
相同)。
问题的唯一其他合理含义是“符号”或“标记”只有在它们立即跟随相同的符号时才应被删除。也就是说,a,a,a,b,b,a,a,b,b,b
之类的输入应该变为,,a,,b,,a,,,b
。在第一个解释中,它应该成为,,,,,,a,,,b
。下面的解决方案实现了“第一解释”(在修改后的字符串中只剩下一个a
和一个b
); OP的问题不清楚是否需要哪种解释。如果需要“第二种解释”,可以修改下面的解决方案(使用基本的“Tabibitosan方法”来识别连续的相同值)。
解决方案分割每个字符串 - 仔细,因为可能有NULL
个标记,然后它标识每个不同符号的最后一个匹配项,替换所有空标记和所有不是“最后一组”的标记占位符符号(这里我用'〜' - 它应该是输入字符串中未使用的符号),然后用LISTAGG()
聚合所有内容并删除所有占位符符号(~
)。需要占位符是因为LISTAGG()
从输入中删除了NULL
(Oracle开发人员做出了令人遗憾的选择)。
该解决方案使用正则表达式;如果性能非常重要,则可以避免使用它们(使用INSTR
和SUBSTR
) - 代价是使代码更复杂。
with
-- begin test data definition (do not include in final query)
test_data as (
select 1 as id, 'a,a,a,b,b,c' as str from dual union all
select 2 , '' from dual union all
select 3 , 'a,b,a,b,b,a' from dual union all
select 4 , 'x,y,z,z,z' from dual union all
select 5 , 'a,a,a,a' from dual union all
select 6 , 'a,b,c,c,a' from dual union all
select 7 , 'x' from dual union all
select 8 , 'p,q,r' from dual union all
select 9 , 'a,b,,,a,c' from dual
),
-- end of test data; solution (query) continues below this line
prep as (
select id, str, level as lvl,
regexp_substr(str, '([^,]*)(,|$)', 1, level, null, 1) as token
from test_data
connect by level <= regexp_count(str, ',') + 1
and prior id = id
and prior sys_guid() is not null
),
with_rn as (
select id, str, lvl, token,
row_number() over (partition by id, token order by lvl desc) as rn
from prep
)
select id, str,
translate( listagg ( case when token is null or rn > 1 then '~'
else token end, ','
) within group (order by lvl), 'x~', 'x'
) as modif_str
from with_rn
group by id, str
;
<强>输出强>:
ID STR MODIF_STR
--- -------------- --------------
1 a,a,a,b,b,c ,,a,,b,c
2
3 a,b,a,b,b,a ,,,,b,a
4 x,y,z,z,z x,y,,,z
5 a,a,a,a ,,,a
6 a,b,c,c,a ,b,,c,a
7 x x
8 p,q,r p,q,r
9 a,b,,,a,c ,b,,,a,c
9 rows selected.
答案 2 :(得分:-1)
一种解决方案是使用两个regexp_replace()
s:
select regexp_replace(regexp_replace('a,a,a,b,b,c', 'a', null, 1, 1), 'b', null, 1, 1)
from dual;
我不确定是否存在使用单个正则表达式的(合理)解决方案。