Oracle:一个复杂案例的正则表达式

Posted

技术标签:

【中文标题】Oracle:一个复杂案例的正则表达式【英文标题】:Oracle: regexp for a complicated case 【发布时间】:2018-12-29 06:08:01 【问题描述】:

我有一张表,其中一列包含一个字符串,其中的项目用分号(;)分隔

我想根据字符串的模式有选择地将数据传输到新表中。

例如,它可能看起来像

16;;14;30;24;11;13;14;14;10;13;18;15;18;24;13/18;11;;23;12;;19;10;;11 ;26;;;42;26;38/39;12;;;;;;;11;;;;;;;;;;;;;;;

11;;11;11;11;11;11;11;11;11;11;11;11;11;11;11;11;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;

我不关心分号之间的内容,但我关心哪些位置包含项目。例如,如果我只希望第 1、3、4 个位置包含项目,我将允许以下...

32;;14;18/12;;;;;;;;;或 32;;14;18/12;;;;55;;;;11;;;;;;;

下面这个不行,因为第三个位置没有任何价值。

32;;;18/12;;;;;;;;;;

如果正则表达式适用于此,那么我可以使用merge into 将所需的记录移动到目标表中。如果无法做到这一点,我将不得不在 Java 中处理每条记录,并有选择地将记录插入到新表中。

源表:

id | StringValue | count

目标表:

id | StringValue | count

我想到的sql:

merge into you_target_table tt
using ( select StringValue, count
        from source_table where REGEXP_LIKE ( StringValue, 'some pattern')
      ) st
on ( st.StringValue = tt.StringValue and st.count=tt.count )
when not matched then
   insert (id, StringValue , count) 
   values (someseq.nextval, st.value1, st.count)
when matched then
   update
   set tt.count = tt.count + st.count;

另外我确定源表中的所有StringValue都是唯一的,所以when matched then之后的内容并不重要,但由于语法,我想我必须有一些东西。

【问题讨论】:

【参考方案1】:

对于每个位置,您都需要一个值 [^;]+;,它匹配任何字符,不是;,并且至少出现一次,后跟;。如果您不关心职位,请输入[^;]*;。这几乎与第一个相似,但; 之前的字符也可能没有。使用^ 将整个事情锚定到开头。

因此,对于您的第 1、第 3 和第 4 位置示例,您将获得:

^[^;]+;[^;]*;[^;]+;[^;]+;

在一个看起来像这样的查询中:

SELECT *
       FROM elbat
       WHERE regexp_like(nmuloc, '^[^;]+;[^;]*;[^;]+;[^;]+;');

db<>fiddle

可以通过将子表达式放在一个组中来进一步改进,即在它们周围加上括号,并使用量词——组后花括号中的数字。例如([^;]+;)2 将匹配两个不为空的位置。您的示例将缩短为:

^[^;]+;[^;]*;([^;]+;)2

【讨论】:

【参考方案2】:

虽然@stiky bit 的答案完全正确,但还有另一个类似但可能更具可读性的解决方案:

SELECT *
   FROM elbat
   WHERE regexp_substr(nmuloc, '(.*?)(;|$)', 1, 1, '', 1) is not null
   AND   regexp_substr(nmuloc, '(.*?)(;|$)', 1, 3, '', 1) is not null
   AND   regexp_substr(nmuloc, '(.*?)(;|$)', 1, 4, '', 1) is not null;

db<>fiddle

优点:

明确指出不应为空的位置编号 具有适用于任何条件的通用模式,因此无需更改正则表达式 可以使用任何正则表达式作为分隔符,而不仅仅是单个字符 实际提取项目,因此您可以使用任何功能进一步测试它

缺点:

相当冗长 慢 n 倍,其中 n 是条件计数 每个非定界符号的回溯速度更慢(最多 2 倍)

但是,根据我的经验,如果查询不是针对数十亿行运行,则这种效率差异很小。即便如此,磁盘读取也会消耗大部分时间。

它是如何制作的:

(.*?)(;|$) - 懒惰地搜索任何以分隔符或字符串结尾结尾的字符序列(可能为零长度) 1 - 开始搜索的位置。 1 是默认值。只需要进入下一个参数 1、3 或 4 - 出现次数或模式 '' - 匹配参数。可用于设置匹配模式,但这里也只能到达最后一个参数 1 - 子表达式编号使 regexp_substr 仅返回第一个捕获组。即 (.*?) 即项目本身没有分隔符。

【讨论】:

以上是关于Oracle:一个复杂案例的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

有没有一种简单的方法可以在 Oracle 8 上转换句子案例中的字符串?还是我应该使用正则表达式?

Oracle10g新特性——正则表达式 - 转

带有大写,小写,数字和特殊字符的复杂密码的正则表达式(Python)

oracle 正则表达式?=

oracle 正则表达式?=

MySQL正则表达式