在 Oracle 中使用正则表达式 sql

Using regex in Oracle sql

我想提取某个字符串的两部分。为此,我想使用正则表达式。 例如,字符串是:Big_Dog_0044_0080,我的正则表达式是:Big_Dog_([0-9]+)_?([0-9A-Z]*) 第 1 组将是 0044,第二组将是 0080。

现在我的问题是将其放入 select 语句中: 我用 regex_substr.

试过了

这是我的结果:

 select 
'Big_Dog_0044_0080' as TestString,
regexp_substr('Big_Dog_0044_0080', '([0-9]+)') Group1 , 
regexp_substr('Big_Dog_0044_0080', '([0-9A-Z]*)') Group2 from dual;

我的输出:

TESTSTRING         Group1 Group2
Big_Dog_0044_0080   0044    B

首先,第 2 组是错误的,我希望是 0080。 我在这里做错了什么?

第二个问题,还有其他办法解决吗? 我想使用 5-6 个不同的正则表达式。例如下一个是 ([A-C])_CatWeezle

我的意思是像 select 输入字符串列并检查可能的正则表达式。 如果一个正则表达式匹配,则停止并提取值。

谢谢!

第一部分问题很简单:

SQL> SELECT 'Big_Dog_0044_0080' AS TestString,
  2         REGEXP_SUBSTR ('Big_Dog_0044_0080', '\d+', 1, 1) Group1,
  3         REGEXP_SUBSTR ('Big_Dog_0044_0080', '\d+', 1, 2) Group2
  4    FROM DUAL;

TESTSTRING        GROU GROU
----------------- ---- ----
Big_Dog_0044_0080 0044 0080

SQL>

我不太明白你说 CatWeezle 的意思。

What I am doing wrong here?

正则表达式 '([0-9A-Z]*)' 将匹配字符串中首次出现的零个或多个数字或大写字母字符。对于您的字符串 'Big_Dog_0044_0080' ,第一个字符是大写字母字符 B 以便匹配,第二个字符 i 与您的正则表达式不匹配,因此它不包含在组。

您声明您的字符串与模式匹配:

Big_Dog_([0-9]+)_?([0-9A-Z]*)

然后您可以使用 $ 将模式锚定到字符串的末尾,并且可以使用:

WITH test_data (value) AS (
  SELECT 'Big_Dog_0044_0080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440A80' FROM DUAL
)
SELECT value,
       REGEXP_SUBSTR(value, '([0-9]+)_?([0-9A-Z]*)$', 1, 1, NULL, 1) AS Group1 , 
       REGEXP_SUBSTR(value, '([0-9]+)_?([0-9A-Z]*)$', 1, 1, NULL, 2) AS Group2
FROM   test_data;

输出:

VALUE GROUP1 GROUP2
Big_Dog_0044_0080 0044 0080
Big_Dog_00440080 00440080
Big_Dog_00440A80 00440 A80

(注意:第二行完全匹配第一组,第二组宽度为零,第三行匹配第一组,直到找到非数字字符,然后开始第二组。)

如果分隔下划线是可选的,那么您可能希望使用固定宽度的匹配项(假设每个子字符串都是 4 个字符):

WITH test_data (value) AS (
  SELECT 'Big_Dog_0044_0080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440A80' FROM DUAL
)
SELECT value,
       REGEXP_SUBSTR(value, '([0-9]{4})_?([0-9A-Z]{4})$', 1, 1, NULL, 1) AS Group1 , 
       REGEXP_SUBSTR(value, '([0-9]{4})_?([0-9A-Z]{4})$', 1, 1, NULL, 2) AS Group2
FROM   test_data;

输出:

VALUE GROUP1 GROUP2
Big_Dog_0044_0080 0044 0080
Big_Dog_00440080 0044 0080
Big_Dog_00440A80 0044 0A80

I mean like select the input string column and go through the possible regexp. If one regexp matches, then stop and extract values.

使用CASE表达式:

WITH test_data (value) AS (
  SELECT 'Big_Dog_0044_0080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440080' FROM DUAL UNION ALL
  SELECT 'Big_Dog_00440A80' FROM DUAL UNION ALL
  SELECT 'A_CatWeezle' FROM DUAL
)
SELECT value,
       CASE
       WHEN REGEXP_LIKE(value, '^Big_Dog_(\d{4})_?([0-9A-Z]{4})$')
       THEN REGEXP_SUBSTR(value, '^Big_Dog_(\d{4})_?([0-9A-Z]{4})$', 1, 1, NULL, 1)
       WHEN REGEXP_LIKE(value, '^([A-C])_CatWeezle$')
       THEN REGEXP_SUBSTR(value, '^([A-C])_CatWeezle$', 1, 1, NULL, 1)
       END AS group1,
       CASE
       WHEN REGEXP_LIKE(value, '^Big_Dog_(\d{4})_?([0-9A-Z]{4})$')
       THEN REGEXP_SUBSTR(value, '^Big_Dog_(\d{4})_?([0-9A-Z]{4})$', 1, 1, NULL, 2)
       END AS group2
FROM   test_data;

输出:

VALUE GROUP1 GROUP2
Big_Dog_0044_0080 0044 0080
Big_Dog_00440080 0044 0080
Big_Dog_00440A80 0044 0A80
A_CatWeezle A

db<>fiddle here