sql - Oracle SQL : Is it possible using SUBSTR and INSTR to return ALL Strings in a given text field?

标签 sql regex oracle substr instr

我正在处理一些存储在 VARCHAR2(4000) 列中的数据,这些数据主要是文本注释,但也包含文本中的日期。我编写了一个查询,它使用 SUBSTR 和 INSTR 进行模式匹配并查找日期之前的前导文本值,然后使用 SUBST 返回日期值,然后使用 TO_DATE 将其转换为日期。这很有效,但是我有许多记录包含多个评论,因此包含多个日期。使用上述方法我只能指定此模式的第(n)次出现,是否有一种方法可以在匹配时返回所有日期而不是仅返回一次出现?

这是 varchar 列中的数据示例;

LOCKED ENTITY: ACCOUNT
LOCKED BY USER: ops
LOCKED AT: 31/05/2004 11:47
CUST NOTES: <Please enter explanation here>
Customer notes are entered here.

UNLOCKED ENTITY: ACCOUNT
UNLOCKED BY USER: ops
UNLOCKED AT: 31/05/2004 11:49
UNLOCK NOTES: <Please enter explanation here>
Test

LOCKED ENTITY: USER
LOCKED BY USER: ops
LOCKED AT: 31/05/2004 11:50
LOCK NOTES: <Please enter explanation here>
Test

UNLOCKED ENTITY: USER
UNLOCKED BY USER: ops
UNLOCKED AT: 24/08/2009 16:47
UNLOCKED NOTES: <Please enter explanation here>

这是我正在使用的查询的简化版本(为了清楚起见,删除了所有其他不相关的联接和列);

select substr(VALUE, INSTR(VALUE,'LOCKED AT: ',1)+11, 10) as "DATE"
  from tableA a
  join tableB b
    on a.id = b.id
 where regexp_like (VALUE ,'ABC|DEF|GHI');  

DATE
----------
31/05/2004

对于上述查询,我​​想返回字符串“LOCKED AT:”之后的所有日期,例如;

 DATE
----------
31/05/2004
31/05/2004

如有任何帮助,我们将不胜感激。有关数据库版本是 Oracle 10g 的信息,我尝试使用 REGEXP_COUNT 来实现我的想法,但仅适用于 11g 及以上版本。

非常感谢

最佳答案

您可以将regexp_substrconnect by level结合使用来获取所有匹配项:

提供示例数据:

WITH tableA(VALUE) AS (SELECT 'LOCKED ENTITY: ACCOUNT
LOCKED BY USER: ops
LOCKED AT: 31/05/2004 11:47
CUST NOTES: <Please enter explanation here>
Customer notes are entered here.

UNLOCKED ENTITY: ACCOUNT
UNLOCKED BY USER: ops
UNLOCKED AT: 31/05/2004 11:49
UNLOCK NOTES: <Please enter explanation here>
Test

LOCKED ENTITY: USER
LOCKED BY USER: ops
LOCKED AT: 31/05/2004 11:50
LOCK NOTES: <Please enter explanation here>
Test

UNLOCKED ENTITY: USER
UNLOCKED BY USER: ops
UNLOCKED AT: 24/08/2009 16:47
UNLOCKED NOTES: <Please enter explanation here>' FROM dual)

查询:

select ltrim( regexp_substr(VALUE,
                            '^LOCKED AT: ([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{4}\.?)',1,LEVEL,'m'), 
                            'LOCKED AT: ') as "Dates Locked" 
  FROM tableA
 CONNECT BY regexp_substr(VALUE,
                            '^LOCKED AT: ([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{4}\.?)',1,LEVEL,'m') IS NOT null

结果:

Dates Locked
------------
31/05/2004
31/05/2004

此查询的问题是,connect by 是针对整个表执行的 - 为了避免这种情况,一种可能的解决方案是分离这部分并独立地对任何数据行执行它:

SELECT ID, ltrim( regexp_substr(VALUE,
                            '^LOCKED AT: ([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{4}\.?)',1,lvl.column_value,'m'), 
                            'LOCKED AT: ') as "Dates Locked" 
  FROM tableA
  CROSS JOIN table(cast(multiset
    (select level from dual
    connect by regexp_substr(VALUE,
                            '^LOCKED AT: ([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{4}\.?)',1,LEVEL,'m') IS NOT null) 
    as sys.odcinumberlist)) lvl

关于sql - Oracle SQL : Is it possible using SUBSTR and INSTR to return ALL Strings in a given text field?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58556362/

相关文章:

sql - 通过 SQL LOADER 存储日期和时间值

mysql - 将 SQL 语法从 MySQL 5.0 转换为 Oracle 12c

sql - TSQL "FOR BROWSE"选项的用途是什么?

java - JSP、SQL检索数据返回null

sql - SQL 比较和空值的问题

javascript - 用于选择并替换为标题大小写值的正则表达式

regex - AWK 中的正则表达式

正则表达式以点|分号空间分割但忽略 url 例如

mysql - 当产品 ID 相同时将数据复制到列

sql - 执行匿名 block PlSQL 失败