【问题标题】:Oracle query parses XML from blob with headerOracle 查询从带有标头的 blob 中解析 XML
【发布时间】:2011-10-05 06:12:48
【问题描述】:

我在 oracle 10 数据库中有一个表,其中包含一个带有 BLOB(不是 CLOB)的字段。此 BLOB 包含大约 300 字节的固定大小的标头,后跟一个 XML 文档。 blob 的大小可能最大为 1 兆字节。我想创建一个 SQL 查询,它在此文档上使用 XQUERY 从 XML 中提取信息。

所以大致的结构是:

create table tbl(id integer, data blob);

insert into tbl(id,data) value(1,'HEADER <?xml version="1.0"><data>
  <row key="k1" value="v11"/>
  <row key="k2" value="v12"/></data>');

insert into tbl(id,data) value(2,'HEADER <?xml version="1.0"><data>
  <row key="k1" value="v21"/>
  <row key="k1" value="v21B"/>
  <row key="k2" value="v22"/></data>');

我想对该表进行查询,当给定键 k1 时,返回值 v11、v21 和 v21B

我知道这种数据组织并不理想,但无法更改。

【问题讨论】:

    标签: sql xml oracle blob


    【解决方案1】:

    好的,所以首先你必须得到 XML 部分。假设标头和 XML 都是字符数据,并且标头是固定长度的,我可能会使用

    的组合

    dbms_lob.converttoclob 将 blob 转换为 clob dbms_lob.substr 获取具有 XML 部分的 clob xmltype.createXML (clob) 将 XML 分配给您的 xmltype xmltype.extract 应用您的 xpath 表达式

    如果标头不是字符数据,您仍然可以使用 dbms_lob.substr,但它会返回您需要转换的 RAW。如果标头不是固定长度,您可以搜索

    因此,基于 cmets,使用类似这样的东西来构建一个包含您想要的内容的 clob,其中 offset 是实际 XML 开头的字节数。修改以传入您的 blob 或 clob。然后在最后应用你的 xpath 而不是我的 dbms_output。

    declare
       v_buffer varchar2(32767);
       v_offset integer := 5;
       v_xml xmltype;
       v_clob clob;
       v_input clob := 'xxxx<?xml version="1.0" encoding="UTF-8"?><test>This is a test</test>';
       i integer := 0;
    begin
       dbms_lob.createtemporary (v_clob,true);
       v_buffer := dbms_lob.substr(v_input,32767,v_offset);
       while length (v_buffer) > 0 loop
          v_clob := v_clob || v_buffer;
          i := i + 1;
          v_buffer := dbms_lob.substr(v_input,32767, v_offset + i * 32767);
       end loop;
       dbms_output.put_line ('x'||v_clob||'x');
       v_xml := xmltype.createXML (v_clob); 
       dbms_lob.freetemporary (v_clob);
       dbms_output.put_line (v_xml.getclobval);
    end;
    

    【讨论】:

    • 我试过了。据我了解, dbms_lob.substr 将 XML 截断为 32767 字节,但最大可达 1MB
    • 你说得对,规范是 DBMS_LOB.SUBSTR ( lob_loc IN CLOB CHARACTER SET ANY_CS, amount IN INTEGER := 32767, offset IN INTEGER := 1) RETURN VARCHAR2 CHARACTER SET lob_loc%CHARSET;所以你需要循环。首先调用获取前 32K 字节,然后使用偏移量 32768 调用并将缓冲区附加到您的 clob,依此类推。
    • 这就是我卡住的地方:我如何在一个 SELECT 中聚合所有这些 32K 部分?或者如果我把它放在一个 BEGIN...END 块中,我可以从这个块返回数据,就好像它是一个 SELECT 一样?另外,由于我只有模式的读取权限,我如何在内存中连接所有这些 32K 部分而不会再次达到 32K 限制?
    • 谢谢,我试试这个。它似乎涵盖了我所有的问题
    猜你喜欢
    • 1970-01-01
    • 2019-06-05
    • 2019-09-02
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    相关资源
    最近更新 更多