【问题标题】:Oracle sql regular expressionOracle sql 正则表达式
【发布时间】:2015-08-02 19:30:42
【问题描述】:

我有一个类似'abc : efg : xyz' 的字符串作为表中的一列,该列的所有记录都是这样的。我想在最后一个冒号(:)之后这个字符串的子字符串。请确实需要帮助

示例:

'abc : efg : xyz'  -> xyz  </br>

'abc : efg : efghj'-> efghj

我有如下查询,但我想比这个查询更短:

SELECT REPLACE (
          REGEXP_SUBSTR (
             'abc : efg : xyz',
             ':.*$',
             REGEXP_INSTR (
                'abc : efg : xyz',
                ':',
                1,
                  LENGTH ('abc : efg : xyz')
                - LENGTH (
                     REPLACE ('abc : efg : xyz',
                              ':',
                              NULL))),
             1),
          ': ') data_after_the_last_colon
  FROM DUAL

【问题讨论】:

    标签: sql regex oracle


    【解决方案1】:

    你想要的是:

    REGEXP_REPLACE (INPUTSTR, '^([^:]+ : )*', '')
    

    具体来说,这会寻找一个从开头(初始插入符号^)开始的字符串,其中出现零次或多次非冒号([^:]+)后跟:。它将所有以空格-冒号-空格结尾的前导字符串替换为空字符串。

    以下查询演示了它是如何工作的。我已经使用了带有您的示例输入和六个其他测试的分解子查询,查询输出具有输入、我的 regexp_replace 结果和您的REPLACE (REGEXP_SUBSTR 语法(我用分解子查询替换了您的' abc : efg : xyz ')。您可以通过复制union all select 行并更改inputstr 的字符串来添加另一个测试用例。

    哦,关于doold——你的语法无法处理没有冒号的输入字符串,它会抛出一个错误,杀死所有查询结果。因此,我将您的语法包装在 DECODE (doold 中以取回所有行。

    with sampl as (
      select           'abc : efg : xyz' as inputstr, 1 as doold from dual
      union all select 'z : b :' as inputstr, 1 as doold  from dual
      union all select 'z : b : ' as inputstr, 1 as doold  from dual
      union all select ' : a ' as inputstr, 1 as doold  from dual
      union all select ' a ' as inputstr, 0 as doold  from dual
      union all select '' as inputstr, 1 as doold  from dual
      union all select ' hij : klm : nop : qrs : tuv' as inputstr, 1 as doold  from dual
    )
    SELECT 
      inputstr,
      regexp_replace (inputstr, '^([^:]+ : )*', '') as bettr,
      decode (doold, 
          1, -- the following is your original expression, for comparison 
             -- purposes, edited only to replace 'abc : efg : xyz' with inputstr
             REPLACE (
              REGEXP_SUBSTR (
                 inputstr,
                 ':.*$',
                 REGEXP_INSTR (
                    inputstr,
                    ':',
                    1,
                      LENGTH (inputstr)
                    - LENGTH (
                         REPLACE (inputstr,
                                  ':',
                                  NULL))),
                 1),
              ': '),
              'Sorry the syntax won''t support input "' || inputstr || '"'
        ) data_after_the_last_colon
      FROM sampl
     order by doold desc, length (inputstr)
    

    【讨论】:

      【解决方案2】:

      正如您所说的模式是固定的,反转字符串并查找并获取子字符串直到第一个分号将是最简单的。您还可以使用trim 消除任何前导/尾随空格。

      select reverse(substr(reverse('abc : efg : efghj'),
                1,instr(reverse('abc : efg : efghj'),':')-1)) from dual
      

      【讨论】:

      • 不幸的是,REVERSE 在 Oracle 中没有记录。
      • @JonHeller..请通过这个..docs.oracle.com/cd/E17952_01/refman-5.1-en/…
      • 那个文件是给 MySQL 的。
      • 我建议你自己试试
      • 它现在可以在我的系统上运行。但它可能不适用于其他系统或将来。 Oracle 表示愿意删除未记录的特性,无论其受欢迎程度如何。例如,WM_CONCAT 是一个未记录但很流行的函数,在 12c 中被删除。如果该函数未列出in one of the manuals,则可能不安全使用。
      【解决方案3】:

      如果INSTR 函数的位置参数为负数,它将从字符串末尾开始倒数。所以你可以使用这样的东西:

      SELECT TRIM(SUBSTR('abc : efg : efghj',INSTR('abc : efg : efghj',':',-1) + 1))
      FROM   dual;
      

      【讨论】:

        【解决方案4】:

        给你。这也适用于 NULL 列表元素:

        SQL> with tbl(row_nbr, str) as (
          2  select 1, 'abc : efg : xyz' from dual
          3  union
          4  select 2, 'abc : efg : efghj' from dual
          5  union
          6  select 3, 'abc :  : efghj' from dual
          7  )
          8  select row_nbr, regexp_substr(str, '(.*?)( : |$)', 1, regexp_count(str, ' \: ')+1, null, 1)
          9  from tbl
         10  order by row_nbr;
        
           ROW_NBR REGEXP_SUBSTR(STR
        ---------- -----------------
                 1 xyz
                 2 efghj
                 3 efghj
        
        SQL>
        

        如果要解析整个列表:

        SQL> with tbl(row_nbr, str) as (
          2  select 1, 'abc : efg : xyz' from dual
          3  union
          4  select 2, 'abc : efg : efghj' from dual
          5  union
          6  select 3, 'abc :  : efghj' from dual
          7      )
          8  SELECT row_nbr, str,
          9             COLUMN_VALUE AS match_nbr,
         10            REGEXP_SUBSTR( str ,'(.*?)( : |$)', 1, COLUMN_VALUE, NULL, 1 ) AS match_value
         11     FROM   tbl,
         12            TABLE(
         13              CAST(
         14                MULTISET(
         15                  SELECT LEVEL
         16                  FROM   DUAL
         17                  CONNECT BY LEVEL <= REGEXP_COUNT( str ,' : ' )+1
         18                ) AS SYS.ODCINUMBERLIST
         19              )
         20            );
        
           ROW_NBR STR                MATCH_NBR MATCH_VALUE
        ---------- ----------------- ---------- -----------------
                 1 abc : efg : xyz            1 abc
                 1 abc : efg : xyz            2 efg
                 1 abc : efg : xyz            3 xyz
                 2 abc : efg : efghj          1 abc
                 2 abc : efg : efghj          2 efg
                 2 abc : efg : efghj          3 efghj
                 3 abc :  : efghj             1 abc
                 3 abc :  : efghj             2
                 3 abc :  : efghj             3 efghj
        
        9 rows selected.
        
        SQL>
        

        【讨论】:

          猜你喜欢
          • 2021-05-22
          • 1970-01-01
          • 2013-12-20
          • 2019-06-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多