我的CLOB文本类似于:
A:123, A:983, A:122, B:232, B:392, C:921, D:221, D:121, D:838
我希望得到类似
的结果A:123, 983, 122, B:232, 392, C:921, D:221, 121, 838
请注意,
这看起来很简单,我们只需要删除CLOB文本中的重复项即可。我无法在SQL中设计逻辑,有人可以建议吗?
更新: 我已经找到了通过自定义Java程序进行迭代和删除重复项的解决方案。这对我来说可以。仍然好奇地看到SQL方法。
答案 0 :(得分:0)
您可以将regexp_substr
与instr
和regexp_count
结合使用:
select listagg(letter||':'||nr,',') within group (order by letter)
as "Result String"
from
(
select letter, listagg(nr,',') within group (order by letter) as nr
from
(
with t(str) as
(
select 'A:123, A:983, A:122, B:232, B:392, C:921, D:221, D:121, D:838' from dual
)
select substr(regexp_substr(str,'[^:]+',instr(str,':'),level),1, instr(str,',')
-instr(str,':')-1) nr,
substr(str,instr(str,':',1,level)-1,1) letter
from t
connect by level < regexp_count(str,'[^:]+')
)
group by letter
);
Result String
-------------------------------------------
A:122,123,983,B:232,392,C:921,D:121,221,838
P.S。您需要to_char
转换为Clob列(即col_clob)。替换
select 'A:123, A:983, A:122, B:232, B:392, C:921, D:221, D:121, D:838' from dual
使用
select to_char(col_clob) from your_table
答案 1 :(得分:0)
此查询解析字符串(搜索冒号),并返回冒号前面的aech字母的字符串出现 second 的位置:
with col as
(select 'A:123, A:983, A:122, B:232, B:392, C:921, D:221, D:121, D:838' col from dual),
t1 as(
select col, instr(col,':',1,level)-1 pos
from col
connect by level <= length(col) - length(replace(col,':',null))
),
t2 as (
select to_char(substr(col,pos,2)) str,
pos
from t1),
t3 as (
select
str, pos,
row_number() over (partition by str order by pos) rn
from t2)
select
str, pos
from t3
where rn = 2
;
基本上,您为每个冒号分割了字符串(我正在使用length(replace
方法来获得比使用正则表达式更好的性能)以提取X:子字符串及其位置。
使用row_number()
来获得第二次出现的partition by str
。
请注意,它可以与任何长度的CLOB一起使用,因为只有长度为2的字符串才转换为VARCHAR。
结果是
STR POS
-------- ----------
A: 8
B: 29
D: 50
解释是
将A:
替换为CLOB中从位置8开始的两个空格。
将CL B:
替换为CLOB中从位置29开始的两个空格。
等
请注意,我要替换为两个空格以不改变字符串中的位置,但这可以轻松增强并替换为NULL。
因此,基本思想是保持前pos-1个字符相同,并replace
保留字符串的其余部分,最后CONCAT
修饰这两个部分:
concat(substr(txt,1, pos-1) , replace( substr(txt, pos), str, ' '));
我在一个函数中实现了整个logik,该函数返回更改后的CLOB,因此可以 在查询和更新语句中都使用了
select id, col, upd_clob(col) from tc;
update tc
set col = upd_clob(col);
功能代码
create or replace function upd_clob(txt CLOB) return CLOB
as
v_txt CLOB := txt;
begin
for r_upd in (
with dt as
(select txt from dual),
t1 as(
select txt, instr(txt,':',1,level)-1 pos
from dt
connect by level <= length(txt) - length(replace(txt,':',null))
),
t2 as (
select to_char(substr(txt,pos,2)) str,
pos
from t1),
t3 as (
select
str, pos,
row_number() over (partition by str order by pos) rn
from t2)
select
str, pos
from t3
where rn = 2)
loop
v_txt := concat(substr(v_txt,1, r_upd.pos-1) , replace( substr(v_txt, r_upd.pos), r_upd.str, ' '));
end loop;
return(v_txt);
end;
/
您可能会发现大型CLOB的性能不佳(尽管IMO替代REGEXP实施要好得多)。一种可能的调优方法是在函数中使用其他logik来识别短字符串并将其作为VARCHAR字符串进行处理。