2

我有一组包含最少 1 个和最多 3 个值的字符串,格式如下:

123;456;789
123;123;456
123;123;123
123;456;456
123;456;123

我正在尝试编写一个正则表达式,以便我可以找到在同一个字符串上重复的值,所以如果你有123;456;789它会返回null但如果你有123;456;456它会返回456123;456;123返回123

我设法写了这个表达式:

(.*?);?([0-9]+);?(.*?)\2

它的工作原理是在null没有重复值时返回,但它不完全返回我需要的值,例如:对于123;456;456它返回的字符串和它返回123;456;456的字符串123;123;123123;123

我需要的是只返回([0-9]+)表达式部分的值,从我读过的内容来看,这通常是使用非捕获组来完成的。但是要么我做错了,要么 Oracle SQL 不支持这一点,就好像我尝试使用?:语法结果不是我期望的那样。

关于如何在 oracle sql 上进行此操作的任何建议?此表达式的目的是在查询中使用它。

SELECT REGEXP_SUBSTR(column, "expression") FROM DUAL;

编辑:

实际上根据https://docs.oracle.com/cd/B12037_01/appdev.101/b10795/adfns_re.htm

Oracle 数据库实现了符合 POSIX 扩展正则表达式 (ERE) 规范的正则表达式支持。

根据https://www.regular-expressions.info/refcapture.html

POSIX ERE 不支持非捕获组

4

3 回答 3

1

如果您只有三个子字符串,那么您可以使用蛮力方法。它不是特别漂亮,但它应该可以完成这项工作:

select (case when val1 in (val2, val3) then val1
             when val2 = val3 then val2
        end) as repeated
from (select t.*,
             regexp_substr(col, '[^;]+', 1, 1) as val1,
             regexp_substr(col, '[^;]+', 1, 2) as val2,
             regexp_substr(col, '[^;]+', 1, 3) as val3
      from t
     ) t
where val1 in (val2, val3) or val2 = val3;
于 2017-10-02T18:37:27.903 回答
1

此答案描述了如何从正则表达式中选择匹配组。所以使用它,

SELECT regexp_substr(column, '(\d{3}).*\1', 1, 1, NULL, 1) from dual;
#                                                       ^ Select group 1

正则表达式的工作演示(礼貌:OP)。

于 2017-10-03T04:32:42.183 回答
0

请耐心等待并考虑这种不同的方法。以不同的方式看待问题,并以一种使您能够更灵活地查看数据的方式对其进行分解。它可能适用于您的情况,也可能不适用于您的情况,但希望有趣的是要记住总是有不同的方法来解决问题。

如果您将字符串转换为行以便对它们执行标准 SQL 会怎样?这样,您不仅可以计算重复的元素,还可以应用聚合函数来寻找跨集合或其他东西的模式。

那么考虑一下。第一个公用表表达式 (CTE) 构建原始数据集。第二个,tbl_split,将数据转换为列表中每个元素的一行。取消注释紧随其后的选择以查看。最后一个查询从拆分数据中进行选择,显示元素在 id 数据中出现的频率。取消注释 HAVING 行以将输出限制为对于您所追求的数据出现多次的元素。

通过行中的数据,您可以看到如何将其他聚合函数应用于切片和切块以显示模式等。

SQL> with tbl_orig(id, str) as (
     select 1, '123;456;789' from dual union all
     select 2, '123;123;456' from dual union all
     select 3, '123;123;123' from dual union all
     select 4, '123;456;456' from dual union all
     select 5, '123;456;123' from dual
   ),
   tbl_split(id, element) as (
   select id,
          regexp_substr(str, '(.*?)(;|$)', 1, level, NULL, 1) element
   from tbl_orig
   connect by level <= regexp_count(str, ';')+1
   and prior id = id
   and prior sys_guid() is not null
   )
   --select * from tbl_split;
   select distinct id, element, count(element)
   from tbl_split
   group by id, element
   --having count(element) > 1
   order by id;

        ID ELEMENT     COUNT(ELEMENT)
---------- ----------- --------------
         1 123                      1
         1 456                      1
         1 789                      1
         2 123                      2
         2 456                      1
         3 123                      3
         4 123                      1
         4 456                      2
         5 123                      2
         5 456                      1

10 rows selected.

SQL>
于 2017-10-04T15:18:01.967 回答