PLSQL 从字符串末尾开始显示数字

PLSQL show digits from end of the string

我有以下问题。 有一个字符串:

There is something 2015.06.06. in the air 1234567 242424 2015.06.07. 12125235

我只需要显示此字符串中的最后一个日期:2015.06.07。 我尝试使用 regexp_substrinsrt,但它不起作用。 所以这只是测试,如果我可以用这个解决方案解决这个问题,我应该将它用于有多个日期的 CLOB 查询,我只需要最后一个。我知道有regexp_count,它有助于解决这个问题,但我使用的数据库是Oracle 10g,所以它不会工作。

有人可以帮助我吗?

regexp_substr 上的文档中,我立即看到一个问题:

.(句点)匹配任何字符。您需要使用反斜杠转义那些字符:\. 以便仅匹配句点字符。

作为参考,我正在链接 this post,这似乎是您对 substrinstr 采取的方法。

Relevant documentation 来自 Oracle:

INSTR(string , substring [, position [, occurrence]])

When position is negative, then INSTR counts and searches backward from the end of string. The default value of position is 1, which means that the function begins searching at the beginning of string.

这里的问题是你的正则表达式只有 returns 一个值,正如 here 所解释的那样,所以你将为 instr 函数提供适当的匹配多个日期。

现在,由于这个限制,我建议使用 this question 中提出的方法,即反转整个字符串(和您的正则表达式,即 \d{2}\.\d{2}\.\d{4}),然后第一个匹配项将是 'last match'。然后,再进行一次字符串反转,得到原来的日期格式。

也许这不是最好的解决方案,但应该可行。

找到这个问题的解决方案的关键是反转 中出现的字符串中的单词的想法。

以下是可能的解决方案:

WITH words AS
(
SELECT regexp_substr(str, '[^[:space:]]+', 1, LEVEL) word, 
        rownum rn
   FROM (SELECT 'There is something 2015.06.06. in the air 1234567 242424 2015.06.07. 2015.06.08 2015.06.17. 2015.07.01. 12345678999 12125235' str
           FROM dual) tab
CONNECT BY LEVEL <= LENGTH(str) - LENGTH(REPLACE(str, ' ')) + 1
)
, words_reversed AS 
(
SELECT *
  FROM words
 ORDER BY rn DESC
)
SELECT regexp_substr(word, '\d{4}\.\d{2}\.\d{2}', 1, 1)
  FROM words_reversed
 WHERE regexp_like(word, '\d{4}\.\d{2}\.\d{2}')
   AND rownum = 1;

可以通过三种不同的 PL/SQL 函数帮助您。

  1. INSTR 函数将识别日期字符串中第一个 "period" 出现的位置。
  2. SUBSTR 使用 (1) 中的值作为起点应用于整个字符串
  3. TO_DATE 对于特定日期掩码:YYYY.MM.DD 会将 (2) 的结果转换为 Oracle 日期时间类型。

要在过程代码中进行这项工作,标准块适用:

 DECLARE
    v_position pls_integer;
    ... other variables
 BEGIN
    sql code and function calls;

 END

SQL Fiddle

Oracle 11g R2 架构设置:

CREATE TABLE finddate
    (column1 varchar2(11), column2 varchar2(39))
;

INSERT ALL 
    INTO finddate (column1, column2)
         VALUES ('row1', '1234567 242424 2015.06.07. 12125235')
    INTO finddate (column1, column2)
         VALUES ('string2', '1234567 242424 2015.06.07. 12125235')
SELECT * FROM dual
;

查询 1:

select instr(column2,'.',1) from finddate
where column1 = 'string2'

select substr(column2,(20-4),10) from finddate

select to_date('2015.06.07','YYYY.MM.DD') from finddate

Results:

| TO_DATE('2015.06.07','YYYY.MM.DD') |
|------------------------------------|
|             June, 07 2015 00:00:00 |
|             June, 07 2015 00:00:00 |

这是一种使用 regexp_replace() 的方法,它应该适用于 10g,假设行的格式相同:

with tbl(col_string) as
(
  select 'There is something 2015.06.06. in the air 1234567 242424 2015.06.07. 12125235' 
  from dual
)
select regexp_replace(col_string, '^.*(\d{4}\.\d{2}\.\d{2})\. \d*$', '')
from tbl;

正则表达式可以读作:

^   - Match the start of the line
.   - followed by any character
*   - followed by 0 or more of the previous character (which is any character)
(   - Start a remembered group
\d{4}\.\d{2}\.\d{2} - 4 digits followed by a literal period followed by 2 digits, etc
)   - End the first remembered group
\.  - followed by a literal period
    - followed by a space
\d* - followed by any number of digits
$   - followed by the end of the line

regexp_replace 然后将所有内容替换为第一个记住的组 (\1)。

基本上将整行描述为一个正则表达式,围绕你想要的进行分组return。如果它可能是数字以外的其他字符,您很可能需要调整行尾的正则表达式,但这应该会给您一个想法。

为了论证,这也有效仅当日期模式出现 2 次时:

with tbl(col_string) as
(
  select 'There is something 2015.06.06. in the air 1234567 242424 2015.06.07. 12125235' from dual
)
select regexp_substr(col_string, '\d{4}\.\d{2}\.\d{2}', 1, 2)
from tbl;

returns 该模式第二次出现。我希望以上 regexp_replace 更准确地描述解决方案。