POSIX ERE 查找重复子串的正则表达式
POSIX ERE Regular expression to find repeated substring
我有一组字符串,其中至少包含 1 个值,最多包含 3 个值,格式如下:
123;456;789
123;123;456
123;123;123
123;456;456
123;456;123
我正在尝试编写一个正则表达式,以便我可以找到在同一个字符串上重复的值,所以如果你有 123;456;789
它会 return null
但如果你有123;456;456
它将 return 456
并且对于 123;456;123
return 123
我设法写出了这个表达式:
(.*?);?([0-9]+);?(.*?)
它的工作原理是它 returns null
当没有重复值但它不 return 正是我需要的值时,例如:对于字符串123;456;456
it returns 123;456;456
对于字符串 123;123;123
it returns 123;123
我需要的只是 return 表达式的 ([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 Database implements regular expression support compliant with the POSIX Extended Regular Expression (ERE) specification.
根据https://www.regular-expressions.info/refcapture.html
Non-capturing group is not supported by POSIX ERE
如果你只有三个子串,那么你可以使用暴力破解的方法。它不是特别漂亮,但它应该能胜任:
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;
This answer 描述了如何 select 来自正则表达式的匹配组。所以使用它,
SELECT regexp_substr(column, '(\d{3}).*', 1, 1, NULL, 1) from dual;
# ^ Select group 1
Working demo 正则表达式(由 OP 提供)。
请耐心等待并考虑这种不同的方法。以不同的方式看待问题,并以一种让您更灵活地查看数据的方式将其分解。它可能适用于您的情况,也可能不适用于您的情况,但希望记住总是有不同的方法来解决问题。
如果您将字符串变成行以便您可以对它们执行标准 SQL 会怎么样?这样,您不仅可以对重复的元素进行计数,还可以应用聚合函数来寻找跨集合或其他东西的模式。
那就考虑一下吧。第一个 Common Table Expression (CTE) 构建原始数据集。第二个 tbl_split 将该数据转换为列表中每个元素的一行。取消注释紧随其后的 select 以查看。来自拆分数据的最后一个查询 selects,显示元素在 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>
我有一组字符串,其中至少包含 1 个值,最多包含 3 个值,格式如下:
123;456;789
123;123;456
123;123;123
123;456;456
123;456;123
我正在尝试编写一个正则表达式,以便我可以找到在同一个字符串上重复的值,所以如果你有 123;456;789
它会 return null
但如果你有123;456;456
它将 return 456
并且对于 123;456;123
return 123
我设法写出了这个表达式:
(.*?);?([0-9]+);?(.*?)
它的工作原理是它 returns null
当没有重复值但它不 return 正是我需要的值时,例如:对于字符串123;456;456
it returns 123;456;456
对于字符串 123;123;123
it returns 123;123
我需要的只是 return 表达式的 ([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 Database implements regular expression support compliant with the POSIX Extended Regular Expression (ERE) specification.
根据https://www.regular-expressions.info/refcapture.html
Non-capturing group is not supported by POSIX ERE
如果你只有三个子串,那么你可以使用暴力破解的方法。它不是特别漂亮,但它应该能胜任:
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;
This answer 描述了如何 select 来自正则表达式的匹配组。所以使用它,
SELECT regexp_substr(column, '(\d{3}).*', 1, 1, NULL, 1) from dual;
# ^ Select group 1
Working demo 正则表达式(由 OP 提供)。
请耐心等待并考虑这种不同的方法。以不同的方式看待问题,并以一种让您更灵活地查看数据的方式将其分解。它可能适用于您的情况,也可能不适用于您的情况,但希望记住总是有不同的方法来解决问题。
如果您将字符串变成行以便您可以对它们执行标准 SQL 会怎么样?这样,您不仅可以对重复的元素进行计数,还可以应用聚合函数来寻找跨集合或其他东西的模式。
那就考虑一下吧。第一个 Common Table Expression (CTE) 构建原始数据集。第二个 tbl_split 将该数据转换为列表中每个元素的一行。取消注释紧随其后的 select 以查看。来自拆分数据的最后一个查询 selects,显示元素在 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>