【问题标题】:Oracle regular expression split string from last occurenceOracle 正则表达式从最后一次出现拆分字符串
【发布时间】:2016-09-15 00:00:41
【问题描述】:

我还在oracle中学习正则表达式我卡在中间了,下面是我的示例代码:

with t(val)
as
(
  --format: xyz_year_month_date
  select 'my_new_table_2015_06_31' from dual
  union all
  select 'my_new_table_temp_2016_06_31' from dual
 )
 select reverse(regexp_substr(reverse(val),'[^_]+',1,4)) col4,
 reverse(regexp_substr(reverse(val),'[^_]+',1,3)) col3,
 reverse(regexp_substr(reverse(val),'[^_]+',1,2)) col2,
 reverse(regexp_substr(reverse(val),'[^_]+',1,1)) col1
 from t;

Output:
COL4 COL3 COL2 COL1
table 2015 06 31
temp 2016 06 31

Expected output:
COL4 COL3 COL2 COL1
my_new_table 2015 06 31
my_new_table_temp 2016 06 31

提前致谢。

【问题讨论】:

    标签: sql regex oracle oracle11g


    【解决方案1】:

    调整您的 col4 正则表达式以匹配字符串的其余部分。最后一个参数表示正则表达式匹配中的捕获组,第二个也是最后一个参数仅在语法上是必需的(它包含匹配参数)。

    对 cols 1-3 的外部 substr 调用去掉了匹配项中的下划线。

    with t(val)
    as
    (
      --format: xyz_year_month_date
      select 'my_new_table_2015_06_31' from dual
      union all
      select 'my_new_table_temp_2016_06_31' from dual
     )
     select reverse(regexp_substr(reverse(val),'([^_]+_){3}(.*)',1,1,'',2)) col4,
     substr(reverse(regexp_substr(reverse(val),'[^_]+_',1,3)), 2) col3,
     substr(reverse(regexp_substr(reverse(val),'[^_]+_',1,2)), 2) col2,
     substr(reverse(regexp_substr(reverse(val),'[^_]+_',1,1)), 2) col1
     from t;
    

    【讨论】:

    • Oracle 11g 确实支持使用 REGXP_SUBSTR() 提取捕获组 - 他们添加了第 6 个参数,您可以在其中指定要返回的捕获组。
    • @MT0 你说得对,我记得oracle版本介绍错了。
    【解决方案2】:

    您可以通过提取不同的捕获组(在()圆括号中)来实现,而无需双重反转:

    WITH t ( VAL ) AS (
      SELECT 'my_new_table_2015_06_31' FROM DUAL UNION ALL
      SELECT 'my_new_table_temp_2016_06_31' FROM DUAL
    )
    SELECT REGEXP_SUBSTR( val, '^(.*)_([^_]+)_([^_]+)_([^_]+)$', 1, 1, NULL, 1 ) AS COL4,
           REGEXP_SUBSTR( val, '^(.*)_([^_]+)_([^_]+)_([^_]+)$', 1, 1, NULL, 2 ) AS COL3,
           REGEXP_SUBSTR( val, '^(.*)_([^_]+)_([^_]+)_([^_]+)$', 1, 1, NULL, 3 ) AS COL2,
           REGEXP_SUBSTR( val, '^(.*)_([^_]+)_([^_]+)_([^_]+)$', 1, 1, NULL, 4 ) AS COL1
    FROM   t
    

    你甚至可以使正则表达式更简单,只需使用:

    '^(.+)_(.+)_(.+)_(.+)$'
    

    第一个.+ 是贪婪的,所以它会尽可能匹配,直到只剩下足够的字符串用于第 2 到第 4 个捕获组的最小匹配。

    但是,您不需要正则表达式

    WITH t ( VAL ) AS (
      SELECT 'my_new_table_2015_06_31' FROM DUAL UNION ALL
      SELECT 'my_new_table_temp_2016_06_31' FROM DUAL
    )
    SELECT SUBSTR( val, 1,        pos1 - 1        ) AS col4,
           SUBSTR( val, pos1 + 1, pos2 - pos1 - 1 ) AS col3,
           SUBSTR( val, pos2 + 1, pos3 - pos2 - 1 ) AS col2,
           SUBSTR( val, pos3 + 1                  ) AS col1
    FROM   (
      SELECT val,
             INSTR( val, '_', -1, 1 ) AS pos3,
             INSTR( val, '_', -1, 2 ) AS pos2,
             INSTR( val, '_', -1, 3 ) AS pos1
      FROM   t
    );
    

    【讨论】:

    • MT0 在这里展示的是您无论如何都需要学习的技术。 “括号中的东西”被称为“捕获组”或“反向引用”,或者在 Oracle 术语中简称为“子表达式”。仅在Oracle 11.1 及以上版本可用,子表达式可以在regexp_substr 中使用:docs.oracle.com/cd/B28359_01/server.111/b28286/functions138.htm 具体阅读文档中对子表达式的解释(包括示例)。
    • 另外,考虑到 null 的可能性(如果第一部分为空怎么办,如 _2013_04_10?) - 而不是 .+ 你可以使用 .* 你已经知道了。跨度>
    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 2016-12-22
    • 2017-08-15
    • 2021-01-02
    相关资源
    最近更新 更多