Oracle中的字符串顺序分组

时间:2015-05-19 05:37:39

标签: sql regex oracle oracle11g

我的任务是将给定字符串中的相似数字/字符分组, 例如: 字符串4455599的SQL输出应为44 555 99,并且正在使用以下查询:

with t(str)
as (
  select '4455599' from dual
)
select listagg(str_grouped ,' ') within group (order by rownum) str_split
from(
    select listagg ( str) within group ( order by lvl) str_grouped
    from(
        select level lvl, 
               substr(str,level,1) str, 
               dense_rank() over( order by substr(str,level,1)) drank_no
        from t
          connect by level <= length(str)
    )
 group by drank_no
  );

但是查询因以下数据而失败,因为我目前正在使用dense_rank

445559944,预计44 555 99 44但获得4444 555 99

bb119911,预计bb 11 99 11但获得1111 99 bb

帮助我,欢迎所有正则表达式查询。

1 个答案:

答案 0 :(得分:9)

对救援的反思:

select 
    regexp_replace('4455599', '((.)\2*)', '\1 ')
from dual;

输出:

44 555 99 

<强>解释

((.)\2*)定义了两个捕获组:

(.)匹配任何单个字符并在第2组中捕获它。

\2*是对第2组中捕获的角色的反向引用,它将相同的角色匹配零次或多次。

因此,

((.)\2*)匹配一个或多个相同字符的序列,并捕获组1中的序列。

\1 替换与第1组内容匹配的字符,后跟空格。

反向引用从左到右计数从1开始(组0是整个匹配)。因此,如果您使用模式(((a)b)c)d,则最内层(a)为第3组,((a)b)为第2组,(((a)b)c)为第1组,如果您使用正常正则表达式引擎(不是oracle&#39; s),整个模式(((a)b)c)d在组0中被捕获。

测试用例

select 
    val, regexp_replace(val, '((.)\2*)', '\1 ') as result
from (
    select '445559944' as val from dual
    union all select 'bb119911' as val from dual
    union all select '46455599464' as val from dual
) foo;

输出:

VAL         RESULT
----------- ------------------
445559944   44 555 99 44 
bb119911    bb 11 99 11 
46455599464 4 6 4 555 99 4 6 4