Oracle 解析来自 clob 的标签之间的数据
Oracle parsing data between tags from a clob
我遇到这样一种情况,应用程序将文本块存储在 CLOB 中。
每个文本块都被一个标签包围
[SYSDATE](请参阅下面的测试案例)。
我正在寻找可以提取匹配标签之间数据的查询。例如,如何获取 [11-22-2021 14:16:19] 之间的文本
所有比赛的标签。在这种情况下 'ZZZZZZZZZZZZZZZZZZZZ'
其次,有没有更好的方法来处理这种情况?也许可以使用 XML?非常感谢所有输入、想法和工作示例。
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE table t(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
c CLOB DEFAULT ' ',
create_date DATE DEFAULT SYSDATE
);
/
insert into t (c) values (' ')
/
CREATE OR REPLACE PROCEDURE lob_append(
p_clob IN OUT CLOB,
p_text IN VARCHAR2
)
AS
l_text varchar2(32760);
l_date_string VARCHAR2(50);
BEGIN
select '[' || TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS') || ']'
into l_date_string from dual;
-- newline each time code is appended for clarity.
l_text :=chr(10) || l_date_string || chr(10)
|| p_text || chr(10)
|| l_date_string||chr(10);
dbms_lob.writeappend(p_clob, length(l_text), l_text );
END;
/
DECLARE
l_clob CLOB := empty_clob();
lTime date;
BEGIN
lTime := sysdate;
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Z',20,'Z'));
loop
exit when sysdate = lTime + interval '5' second;
end loop;
l_clob := empty_clob();
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Y',10,'Y'));
END;
/
SEQ_NUM C CREATE_DATE
1
[11-22-2021 14:16:19]
ZZZZZZZZZZZZZZZZZZZZ
[11-22-2021 14:16:19]
[11-22-2021 14:16:24]
YYYYYYYYYY
[11-22-2021 14:16:24]
11222021 14:15:54
您的示例 CLOB 包含换行符;我认为这是正确的,并明确处理了换行符。 (下面的解决方案假定每个“令牌”本身不包含换行符 - 如果包含,那么您可以稍微修改 regexp_substr
调用,使用允许点元字符匹配换行符的选项。)
select t.seq_num, l.ord, l.token
from t cross join lateral
(
select level as ord,
regexp_substr(c, '(\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])'
|| chr(10) || '(.*?)' || chr(10) || ''
, 1, level, null, 2)
as token
from dual
connect by level <=
regexp_count(c, '(\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])'
|| chr(10) || '(.*?)' || chr(10) || '')
) l
order by seq_num, ord -- if needed
;
SEQ_NUM ORD TOKEN
---------- ---------- -------------------------
1 1 ZZZZZZZZZZZZZZZZZZZZ
1 2 YYYYYYYYYY
添加了create_date输出
SELECT T.SEQ_NUM,
L.ORD,
L.CREATE_DATE,
L.TOKEN
FROM T,
LATERAL(
SELECT LEVEL ORD,
REGEXP_SUBSTR(
C,
'\[(.{19})\]',
1,
LEVEL * 2 - 1,
null,
1
) CREATE_DATE,
REGEXP_SUBSTR(
C,
'(\[.{19}\])(' ||
CHR(10) || '|' || CHR(13) || ')*(.*)(' ||
CHR(10) || '|' || CHR(13) || ')',
1,
LEVEL,
'n',
3
) TOKEN
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT(
C,
'(\[.{19}\])(' ||
CHR(10) || '|' || CHR(13) || ')*(.*)(' ||
CHR(10) || '|' || CHR(13) || ')'
)
) L
order by seq_num, ord;
SEQ_NUM ORD CREATE_DATE TOKEN
1 1 12-01-2021 05:53:22 ZZZZZZZZZZZZZZZZZZZZ
1 2 12-01-2021 05:53:24 YYYYYYYYYY
我遇到这样一种情况,应用程序将文本块存储在 CLOB 中。
每个文本块都被一个标签包围 [SYSDATE](请参阅下面的测试案例)。
我正在寻找可以提取匹配标签之间数据的查询。例如,如何获取 [11-22-2021 14:16:19] 之间的文本 所有比赛的标签。在这种情况下 'ZZZZZZZZZZZZZZZZZZZZ'
其次,有没有更好的方法来处理这种情况?也许可以使用 XML?非常感谢所有输入、想法和工作示例。
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE table t(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
c CLOB DEFAULT ' ',
create_date DATE DEFAULT SYSDATE
);
/
insert into t (c) values (' ')
/
CREATE OR REPLACE PROCEDURE lob_append(
p_clob IN OUT CLOB,
p_text IN VARCHAR2
)
AS
l_text varchar2(32760);
l_date_string VARCHAR2(50);
BEGIN
select '[' || TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS') || ']'
into l_date_string from dual;
-- newline each time code is appended for clarity.
l_text :=chr(10) || l_date_string || chr(10)
|| p_text || chr(10)
|| l_date_string||chr(10);
dbms_lob.writeappend(p_clob, length(l_text), l_text );
END;
/
DECLARE
l_clob CLOB := empty_clob();
lTime date;
BEGIN
lTime := sysdate;
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Z',20,'Z'));
loop
exit when sysdate = lTime + interval '5' second;
end loop;
l_clob := empty_clob();
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Y',10,'Y'));
END;
/
SEQ_NUM C CREATE_DATE
1
[11-22-2021 14:16:19]
ZZZZZZZZZZZZZZZZZZZZ
[11-22-2021 14:16:19]
[11-22-2021 14:16:24]
YYYYYYYYYY
[11-22-2021 14:16:24]
11222021 14:15:54
您的示例 CLOB 包含换行符;我认为这是正确的,并明确处理了换行符。 (下面的解决方案假定每个“令牌”本身不包含换行符 - 如果包含,那么您可以稍微修改 regexp_substr
调用,使用允许点元字符匹配换行符的选项。)
select t.seq_num, l.ord, l.token
from t cross join lateral
(
select level as ord,
regexp_substr(c, '(\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])'
|| chr(10) || '(.*?)' || chr(10) || ''
, 1, level, null, 2)
as token
from dual
connect by level <=
regexp_count(c, '(\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])'
|| chr(10) || '(.*?)' || chr(10) || '')
) l
order by seq_num, ord -- if needed
;
SEQ_NUM ORD TOKEN
---------- ---------- -------------------------
1 1 ZZZZZZZZZZZZZZZZZZZZ
1 2 YYYYYYYYYY
添加了create_date输出
SELECT T.SEQ_NUM,
L.ORD,
L.CREATE_DATE,
L.TOKEN
FROM T,
LATERAL(
SELECT LEVEL ORD,
REGEXP_SUBSTR(
C,
'\[(.{19})\]',
1,
LEVEL * 2 - 1,
null,
1
) CREATE_DATE,
REGEXP_SUBSTR(
C,
'(\[.{19}\])(' ||
CHR(10) || '|' || CHR(13) || ')*(.*)(' ||
CHR(10) || '|' || CHR(13) || ')',
1,
LEVEL,
'n',
3
) TOKEN
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT(
C,
'(\[.{19}\])(' ||
CHR(10) || '|' || CHR(13) || ')*(.*)(' ||
CHR(10) || '|' || CHR(13) || ')'
)
) L
order by seq_num, ord;
SEQ_NUM ORD CREATE_DATE TOKEN
1 1 12-01-2021 05:53:22 ZZZZZZZZZZZZZZZZZZZZ
1 2 12-01-2021 05:53:24 YYYYYYYYYY