【问题标题】:Capture the Substring in oracle在 oracle 中捕获子字符串
【发布时间】:2020-01-03 14:08:41
【问题描述】:

我想搜索从以下类型的字符串中获取子字符串 -

TEST-01-2019/10/10 01:01:20

预期结果 -

TEST-01 

基本上我想提取日期连字符之前的所有内容。 我怎样才能做到这一点?通过正则表达式?

【问题讨论】:

  • 输入字符串总是这样吗?我的意思是,你怎么知道在哪里期待约会?例如,可能是test-01-1996/23/13-2019/10/10 01:01:20(其中 1996/23/23 肯定不是有效日期)。
  • 它将是系统生成的日期,因此它必须是 YYYY/MM/DD 或 YYYY/DD/MM 中的有效日期,但它始终位于带有连字符的字符串之后并以 th 开头年。
  • 好的,谢谢你的解释。我已经发布了一个 SUBSTR + INSTR 选项作为答案;请看一下。

标签: oracle substring


【解决方案1】:

下面的解决方案,使用regexp_replace(),找到模式“破折号,四位数,正斜杠,两位数,正斜杠,两位数,空格,两位数,冒号,两位数,冒号,两位数”,并且如果找到它,它会将它和所有剩余的(后续)字符删除到字符串的末尾。它不验证“日期”(它不检查它是否是有效的日期时间字符串)。如果未找到该模式,则该函数返回原始字符串,保持不变。

注意函数的最后一个参数'n'。当输入字符串包含换行符时(不太可能,但可能)情况就是这样。通常,点. 作为通配符与换行符不匹配; 'n' 修饰符改变了这种行为,允许点也匹配换行符。

with
  test (col) as (
    select 'TEST-01-2019/10/10 01:01:20'                  from dual union all
    select 'something else-goes here-2019/08/30 12:33:00' from dual union all
    select 'TEST/01-2019/10/10 01:01:20'                  from dual union all
    select 'TEST_01-2019/10/10 01:01:20'                  from dual union all
    select 'TEST-01'                                      from dual
  )
select col, 
       regexp_replace(col, '-\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}.*',
                           null, 1, 1, 'n') as result
from   test
;

COL                                          RESULT                        
-------------------------------------------- ------------------------------
TEST-01-2019/10/10 01:01:20                  TEST-01                       
something else-goes here-2019/08/30 12:33:00 something else-goes here      
TEST/01-2019/10/10 01:01:20                  TEST/01                       
TEST_01-2019/10/10 01:01:20                  TEST_01                       
TEST-01                                      TEST-01 

编辑:这是一个仅使用标准字符串函数的解决方案,因此可能比任何使用正则表达式的解决方案都更快(并且可能明显如此)。

select col,
       case when translate(col, '123456789', '000000000') 
                   like '%-0000/00/00 00:00:00%'
            then substr(col, 1, instr(translate(col, '123456789', '000000000'),
                                      '-0000/00/00 00:00:00') - 1)
            else col
       end  as result
from   test
; 

【讨论】:

    【解决方案2】:

    SUBSTR + INSTR 选项:

    SQL> with test (col) as
      2    (select 'TEST-01-2019/10/10 01:01:20'                  from dual union all
      3     select 'something else-goes here-2019/08/30 12:33:00' from dual union all
      4     select 'TEST/01-2019/10/10 01:01:20'                  from dual union all
      5     select 'TEST_01-2019/10/10 01:01:20'                  from dual union all
      6     select 'TEST-01'                                      from dual
      7    )
      8  select col,
      9    substr(col, 1, case when regexp_count(col, '\d+') > 2 then regexp_instr(col, '-\d') - 1
     10                        else length(col)
     11                   end
     12          ) result
     13  from test;
    
    COL                                          RESULT
    -------------------------------------------- ------------------------------
    TEST-01-2019/10/10 01:01:20                  TEST
    something else-goes here-2019/08/30 12:33:00 something else-goes here
    TEST/01-2019/10/10 01:01:20                  TEST/01
    TEST_01-2019/10/10 01:01:20                  TEST_01
    TEST-01                                      TEST-01
    
    SQL>
    

    【讨论】:

    • 任何方式我都可以从后面搜索连字符并选择所有前面的字符串。就像我有 TEST/01-2019/10/10 01:01:20 TEST_01-2019/10/10 01:01:20 TEST_01 b> 所有这些场景也要选择?
    • 我已经编辑了查询;我没有使用 INSTR,而是将其修改为使用 REGEXP_INSTR,找到第一个“连字符后跟一个数字”并获取它前面的所有内容。
    • 编辑后的解决方案并不完全符合 OP 的要求。查看您的第一行:RESULT 应该是 TEST-01,而不仅仅是 TEST。此外,如果您再次修改查询以搜索 '-\d{4}, the solution will fail on an input like TEST-0101-2019/03/20 12:30:00`。
    【解决方案3】:

    尝试使用REGEXP_SUBSTR

    SELECT REGEXP_SUBSTR(col, '^[^-]+-[^-]+')
    FROM yourTable;
    

    Demo

    这将为您提供的输入选择TEST-01。逻辑是匹配的:

    ^          from the beginning of the string
        [^-]+  one or more non dash characters
        -      a literal dash
        [^-]+  one or more non dash characters
    

    这对应于日期之前的部分,至少对于您碰巧向我们展示的样本而言。

    另一种方法可能是正则表达式替换日期字符串,直到输入结束:

    SELECT REGEXP_REPLACE(col, '-[0-9]{4}/[0-9]{2}/[0-9]{2}.*', '')
    FROM yourTable;
    

    Demo

    此正则表达式模式匹配一​​个破折号,后跟 YYYY/MM/DD 格式的日期,然后是直到字符串末尾的所有内容。然后它用空字符串替换这个匹配,有效地将它从输入中删除。

    【讨论】:

    • 谢谢。您能否提供一些详细的解释,说明这两种方法都在做什么
    • 我添加了关于每种方法的作用的描述。
    • 非常感谢您的帮助。还有一件事,它可以Test/01;Test-01/Test;唯一确定的是在 Date 之前会有一个连字符;并且该连字符之前的字符串可以再次包含任何内容; -,/.它也可以是不附加任何日期的 Test-01。因此,我想捕获所有这些记录。在那种情况下,我们有什么办法可以修改 REGEXP_SUBSTR?
    • 如果连字符 + 日期总是出现在字符串的 end 处,并且您总是希望保留较早的部分,那么正则表达式子字符串选项就足够了。否则,它可能不会。
    • 是的,它总是出现在字符串的末尾。但是如果前面的字符串没有'-',那么正则表达式 substr 会起作用吗?就像它似乎不适用于以下场景:TEST/01-2019/10/10 01:01:20 TEST_01-2019/10/10 01:01:20 TEST_01
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多