Oracle中这段正则去重SQL的\1符号及正则逻辑是什么含义?
SQL正则去重拼接逻辑详解
原SQL如下:
SELECT REGEXP_REPLACE(LISTAGG(A.ID, ',') WITHIN GROUP (ORDER BY A.ID), '([^,]+)(,\1)+', '\1') FROM TABLE A
\1的具体含义
\1是正则语法里的反向引用,指代匹配过程中,正则模式里第1个被圆括号包裹的捕获组实际匹配到的文本内容。
完整实现逻辑
这是Oracle 19c版本(该版本首次原生支持LISTAGG(DISTINCT 列, 分隔符)的去重写法)之前,实现字段去重拼接的经典偏方,必须依赖WITHIN GROUP (ORDER BY A.ID)的排序规则才能正常工作,执行流程分两步:
- 第一步执行
LISTAGG聚合:将表A的所有ID按升序排列后,用逗号做分隔符拼接为单个长字符串。因为提前做了排序,取值相同的ID会连续挨在一起,举个实际例子,如果ID列取值是1111、1111、2222、3333、3333,拼接结果就是1111,1111,2222,3333,3333。 - 第二步执行
REGEXP_REPLACE正则替换,匹配模式为([^,]+)(,\1)+,各部分作用:([^,]+):第1个捕获组,匹配1个及以上连续的非逗号字符,刚好对应拼接串里的单个ID值——你用的A.ID是NUMBER(4)类型的纯数字,本身不含逗号,不会出现匹配错位的问题。(,\1)+:匹配「英文逗号 + 第1个捕获组匹配到的完全一致的内容」,要求这个组合连续出现至少1次,本质就是匹配某个ID后面跟着的所有连续重复的,ID片段。
- 替换规则是把匹配到的整段连续重复ID串,替换为单个
\1也就是单个ID值,直接删掉所有多余的重复项。还是以上面的拼接串举例:- 连续重复段
1111,1111会被替换为单个1111 - 没有重复的
2222不会被匹配替换 - 连续重复段
3333,3333会被替换为单个3333
最终输出结果就是1111,2222,3333,达到去重拼接的目的。
- 连续重复段
生效前提
这个写法不是通用去重方案,必须满足LISTAGG内对拼接的ID字段做排序的要求,保证相同ID连续排列。如果去掉排序逻辑,相同ID可能被其他值隔开,比如拼接结果为1111,2222,1111,正则无法识别非连续的重复项,去重就会失效。
内容的提问来源于stack exchange,提问作者eastglow
相关产品推荐
相关产品推荐

