【问题标题】:PLSQL show digits from end of the stringPLSQL 显示字符串末尾的数字
【发布时间】:2015-09-14 22:40:55
【问题描述】:

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

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,所以它不会工作。

有人可以帮帮我吗?

【问题讨论】:

  • 您可以发布您尝试过的正则表达式吗?这将为回答这个问题提供一个更好的起点。
  • select substr('空中有东西 2015.06.06. 1234567 242424 2015.06.07. 12125235', instr('空中有东西 2015.06.06. 1234567 242424 2015.06.07. 12125235',1,-1)-instr('空中有东西2015.06.06. 1234567 242424 2015.06.07. 12125235',regexp_substr('空中有东西2015.06.06. 1234567 242424 2015.06. 12125235','\d\d\d\d.\d\d.\d\d',1 ),-1,1),10) 来自对偶;

标签: sql regex oracle plsql regexp-substr


【解决方案1】:

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

这是可能的解决方案:

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;

【讨论】:

  • 是的,这是一般的想法,但我更多地考虑reversing the entire string 并反转正则表达式,然后再次反转结果。
  • 非常感谢,它运行良好。因此,正如我所写,我尝试使用 instr,但它没有用。您的解决方案完美无缺,但我对较短的解决方案感兴趣。是否有可能在 regexp_substr 中给出从字符串末尾检查的内容?否则谢谢你们俩的帮助。
【解决方案2】:

regexp_substr 的文档中,我立即发现了一个问题:

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

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

Relevant documentation 来自 Oracle:

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

当 position 为负数时,INSTR 从字符串末尾开始计数并向后搜索。 position的默认值为1,表示函数从字符串的开头开始搜索。

这里的问题是您的正则表达式只返回一个值,正如 here 所解释的那样,因此在多个日期的情况下您将为 instr 函数提供适当的匹配。

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

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

【讨论】:

  • 您好,我尝试按照您的建议进行操作,但无法使用。所以首先,我只需要 regexp_substr 子句,之后我可以解决它,但是我尝试了很多方法,它不会奏效。这是我的代码:select instr('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',regexp_substr('There is something in 20.06.08.空气 1234567 242424 2015.06.07. 2015.06.08 2015.06.17. 2015.07.01. 12345678999 12125235','\d\d\d\d\.\d\d\.\d\d',1),- 1,1) 来自双重的 fasz;
【解决方案3】:

有三种不同的 PL/SQL 函数可以帮助您实现目标。

  1. INSTR 函数将识别日期字符串中第一个“句点”出现的位置。
  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 |

【讨论】:

  • 非常感谢。它非常有帮助。最好的问候。
【解决方案4】:

这是一种使用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*$', '\1')
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)。

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

为了论证,这也有效仅当出现 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;

返回模式的第二次出现。我希望上面的 regexp_replace 更准确地描述了解决方案。

【讨论】:

  • 非常感谢。它非常有帮助。
猜你喜欢
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2015-02-02
  • 2013-11-12
  • 1970-01-01
相关资源
最近更新 更多