Sql Oracle:用于复杂案例的regexp

Sql Oracle:用于复杂案例的regexp,sql,regex,oracle,Sql,Regex,Oracle,我有一个表,其中一列包含一个字符串,其中的项用分号(;)分隔 我希望根据字符串的模式有选择地将数据传输到新表 例如,它可能看起来像 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;;;;;;;;;;;;;;

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

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

例如,它可能看起来像

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;;;;;;;;;

如果regexp对此有效,那么我可以使用
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都是唯一的,所以匹配时
后面的内容并不重要,但由于语法的原因,我认为我必须有一些内容。

对于每个位置,您需要放置一个值
[^;]+,它匹配任何字符,而不是
并至少出现一次,后跟一个
。如果您不喜欢某个职位,请输入
[^;]*。这几乎与第一个相似,但字符在
之前也可以是无。用
^
将整个事情锚定到开头

因此,对于您的第一、第三和第四个职位示例,您将获得:

^[^;]+;[^;]*;[^;]+;[^;]+;
在一个如下所示的查询中:

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

它可以通过将子表达式放入一个组来进一步改进,也就是说,在它们周围放上括号,并使用quantors——组后大括号中的数字。例如,
([^;]+;){2}
将匹配两个非空的位置。您的示例将缩短为:

^[^;]+;[^;]*;([^;]+;){2}
虽然答案完全正确,但还有另一个类似但可能更具可读性的解决方案:

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;

优点:

  • 明确说明不应为空的位置编号
  • 在任何情况下都有通用模式,因此无需更改正则表达式
  • 可以使用任何正则表达式作为分隔符,而不仅仅是单个字符
  • 实际上提取项目,所以您可以使用任何函数对其进行进一步测试
缺点:

  • 相当冗长
  • 慢n倍,其中n是条件计数
  • 更慢(最多2倍)的原因是每个非分隔符符号上的回溯
然而,根据我的经验,如果查询不是针对数十亿行运行的,那么这种效率差异是很小的。即使这样,磁盘读取也会占用大部分时间

制作方法:

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