【问题标题】:REGEXP_SUBSTR with negative position具有负位置的 REGEXP_SUBSTR
【发布时间】:2017-02-17 15:06:43
【问题描述】:

我有一个查询将逗号视为字符串中的分隔符。我想取消最后一次出现。

示例:字符串:a、b、c、d 字符串:e、f、g、h、i、j

select regexp_substr(string, '[^,]+', -1, 1)
from dual;

应该返回:d 和 j

但错误信息显示 -1 位置超出范围。

Oracle 文档:https://docs.oracle.com/cd/E11882_01/olap.112/e23381/row_functions063.htm#OLAXS456

【问题讨论】:

  • 第一个字符串中的空格是怎么回事?如果逗号是真正的分隔符,则第一个示例字符串的最后一个“标记”是' d'(长度为 2 的字符串:空格和字母 d)。
  • 我可以接受带空格的字符串。
  • 您发布的文档参考是针对 Oracle OLAP 的,它是一个独立的产品,与 Oracle 数据库不同。如果您安装了 Oracle OLAP(无论如何,我不知道),您可能已经将功能扩展到 regexp_substr 和其他功能,但这与 Oracle 数据库无关。标准 Oracle SQL 的 regexp_substr 文档不允许否定位置。
  • 已确认。谢谢

标签: oracle regexp-substr


【解决方案1】:
SELECT regexp_substr(string, '[^,]*$') FROM t

Test

【讨论】:

  • 这行得通,但是如果我想获得最后的第二次出现怎么办。问题是Oracle文档特别提到使用负整数,该函数将向后搜索。我想知道为什么它不起作用。 quote from oracle: '一个非零整数,指示函数开始搜索的 source_char 字符。当 position 为负数时,该函数从字符串的末尾开始计数并向后搜索。 position的默认值为1,表示函数从source_char的第一个字符开始搜索。'
  • @dozel - Oracle 文档说它应该是一个正整数。 '位置是一个正整数,指示 Oracle 应该开始搜索的 source_char 字符。默认值为 1,表示 Oracle 从 source_char 的第一个字符开始搜索。'
  • @dozel - 这是 11g 文档中的页面 - docs.oracle.com/cd/B28359_01/server.111/b28286/…
  • @Mihai - 请参阅我在原始帖子下的评论。 Oracle OLAP 与 Oracle 数据库不同。
【解决方案2】:

您可以通过以下几种方式做到这一点:

WITH sample_data AS (SELECT 'a, b, c, d' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i, j' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i, jk' str FROM dual UNION ALL
                     SELECT 'e,f,g,h,i,jk' str FROM dual UNION ALL
                     SELECT 'e,f,g,h,i,' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i,' str FROM dual)
SELECT str,
       ltrim(SUBSTR(str, INSTR(str, ',', -1, 1) + 1)) last_item1,
       regexp_substr(str, '.*, ?([^,]*$)', 1, 1, NULL, 1) last_item3
FROM   sample_data;

STR               LAST_ITEM1        LAST_ITEM3
----------------- ----------------- -----------------
a, b, c, d        d                 d
e, f, g, h, i, j  j                 j
e, f, g, h, i, jk jk                jk
e,f,g,h,i,jk      jk                jk
e,f,g,h,i,                          
e, f, g, h, i,                      

这是两个选项之间的折腾,哪个选项在您的系统中具有最高的性能和/或可维护性 - 您需要对此进行测试。

上面的 regexp_substr 解决方案检查任何字符的模式(换行符除外),后跟一个逗号,后跟一个空格(或不是),最后是直到字符串末尾的任何不是逗号的字符。然后我们输出第一个子表达式(通过括号部分模式定义)。

我在 substr/instr 项中包含了 ltrim,因为您说您的分隔符是逗号,但看起来可能是逗号+空格。

【讨论】:

  • 我认为我的问题更多是关于为什么使用 -1 作为位置不起作用,而 oracle 文档特别说如果我们想向后搜索我们可以使用负 int。我可以使用 substr 和 instr,但是当有更简单的方法时,我为什么要这样做。
  • 那是因为您正在查看的文档(它是旧格式,因此很可能已经过时)看起来有一个错误。在 REGEXP_SUBSTR 中的位置或出现处不能有负数。
  • 一个较新的文档也这么说:(docs.oracle.com/cd/E11882_01/olap.112/e23381/…)。但也许你是对的,文档有缺陷。
  • @dozel - 不要将 Oracle OLAP(单独的产品)与标准 Oracle SQL(Oracle 数据库)混淆!
  • @Boneist - 我问过 OP,他/她回答说逗号是真正的分隔符;如果存在空格,则必须保留。 (或者,如果它们被保留,“没关系”。)如果是这样,几乎可以肯定使用标准字符串函数而不是正则表达式的解决方案会更有效。
【解决方案3】:

没有正则表达式的解决方案可能是:

select substr(string, instr( string, ',', -1)+1)
from yourTable

在这里,您使用instr 查找最后出现的“,”(如果有),然后使用substr 仅返回输入字符串的所需部分。

【讨论】:

    【解决方案4】:

    你在评论中问如果你想获得第二次出现怎么办?第 4 个参数是您要返回的元素。这种格式处理 NULL 元素:

    with tbl(str) as (
      select 'a, b, c, d' from dual union
      select 'e,,g,h,i,j' from dual
    )
    select regexp_substr(str, '(.*?)(,|$)', 1, 2, NULL, 1) element
    from tbl; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-25
      • 2016-08-28
      • 1970-01-01
      • 1970-01-01
      • 2016-11-22
      • 2016-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多