我正在处理一些存储在 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_substr
与connect 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/