问题描述
我正在尝试在Oracle中解决如何隔离/突出显示如下所示的串联字符串中的单词组合:
Some words##Again words##More of this||@@@@||Some words##Again words##Other
这个想法是找到出现恰好两次的单词组合,然后将其替换为0,这样我就剩下了只出现一次的单词组合,位于{{1的左侧}}或在右侧。查询结果应该是这样的:
突出显示
||@@@@||
已替换
Some words##Again words##More of this||@@@@||Some words##Again words##**Other**
为您提供有关串联的更多信息:左侧(在0##0##More of this||@@@@||0##0##Other
之前)是我当前的客户记录,而右侧则是以前的版本。通过进行替换,我可以揭示客户记录之间的任何差异。
我尝试通过使用以下方法完成此任务:
- regexp_replace :由于某些原因,我的第一条记录中的字符串部分从未正确替换过,因此不能完全与
||@@@@||
一起使用。由于我需要匹配的单词组合数量,我也达到了此功能的极限; - 嵌套的CASE WHEN :显然不起作用,因为CASE WHEN甚至嵌套-在找到第一个匹配项时停止,但是我需要检查并替换所有条件。
- 我已经考虑过使用子选择,但是由于此查询使用了我的架构中最大的表之一,因此除非按每个客户使用,否则此表将无法使用。而且可能仍然无法正常工作...
我希望这很清楚。有人有一些神奇的主意吗?
预先感谢
解决方法
您可以使用递归子查询分解子句在每次迭代时替换一个重复项:
WITH replaced ( value,start_char ) AS (
SELECT REGEXP_REPLACE(
value,'(##|^)([^#]+?)((##[^#]+?)*\|\|@@@@\|\|([^#]+?##)*)\2(##|$)','\10\30\6',1
),REGEXP_INSTR(
value,1
)
FROM table_name
UNION ALL
SELECT REGEXP_REPLACE(
value,start_char + 1
),start_char + 1
)
FROM replaced
WHERE start_char > 0
)
SELECT value
FROM replaced
WHERE start_char = 0;
其中的示例数据:
CREATE TABLE table_name ( value ) AS
SELECT 'Some words##Again words##More of this||@@@@||Some words##Again words##Other' FROM DUAL UNION ALL
SELECT '333##123##789##555||@@@@||123##456##789##222##333' FROM DUAL;
输出:
| VALUE | | :------------------------------------ | | 0##0##More of this||@@@@||0##0##Other | | 0##0##0##555||@@@@||0##456##0##222##0 |
db 提琴here
说明:
正则表达式匹配:
-
(##|^)
是两个#
字符或字符串^
的开头(在第一个捕获组()
中); -
([^#]+?)
不是#
的一个或多个字符(在第二个翻转组()
中); -
(
第三个捕获组的开始;-
(##[^#]+?)*
两个#
字符,然后是一个或多个非#
字符(在第四捕获组()
中),都重复了零个或多个{ {1}}次; -
*
然后是两个\|\|@@@@\|\|
字符,四个|
字符和两个@
字符; -
|
,然后是一个或多个非([^#]+?##)*
字符,然后是两个#
字符(在第5个捕获组#
中);
-
-
()
第三个捕获组的结尾; -
)
是第二个捕获组的副本;然后 -
\2
要么是两个(##|$)
字符,要么是字符串结尾的#
(在第6个捕获组中)。
将其替换为:
-
$
,它是第一个捕获组的内容,然后是一个零(替换第二个捕获组),然后是第三个捕获组的内容,然后是第二个零(替换匹配的重复项),然后是第六捕获小组。
查询将替换字符串中的一对重复项(如果它们存在),并且\10\30\6
将找到匹配项的开始并将值放入REGEXP_INSTR
和value
(分别);然后在下一次迭代中,正则表达式将从上一个匹配项的开始处的下一个字符开始查找,因此它将在查找匹配项的字符串中逐渐移动,直到找不到更多重复项为止,start_char
不执行替换,REGEXP_REPLACE
将返回REGEXP_INSTR
,并且迭代将终止。
最终查询过滤器仅返回迭代的最终级别(当所有重复项均已替换时)。