【问题标题】:Select and Update Oracle BLOB column with XMLQUERY使用 XMLQUERY 选择和更新 Oracle BLOB 列
【发布时间】:2016-04-19 14:36:13
【问题描述】:

我必须更新存储在 Oracle 11G 中 BLOB 列中的 XML 值。 BLOB 存储了一个完整的 XML 文件,我必须在其中更新一些值并将其另存为 BLOB。如何通过 blob 转换和 XMLQUERY 和 XMLUPDATE 轻松选择和更新数据?任何代码示例?

提前谢谢你。

这里有更多细节:

这是表的ddl:

CREATE TABLE MAPSHEET
(
  MAPSHEETID NUMBER (14,0) NOT NULL,
  NAME VARCHAR2 (64) NOT NULL,
  STRUCTURE BLOB,
)

blob col STRUCTURE 中的 xml 数据

<MapSheet Version="1.0">
    <Frame>
        <JobId>9022165</JobId>
        <LayoutId>24807064</LayoutId>
        <Blocks>
            <Block MapFieldMask="true" CompressText="false" CombineRaster="false">
                <Name>layout</Name>
                <StyleId>24808857</StyleId>
                <LayoutLayers>0 1</LayoutLayers>
                <BlockScale/>
                <JobItemIds/>
            </Block>
            <Block MapFieldMask="true" CompressText="false" CombineRaster="false">
                <Name>karto</Name>
                <StyleId>24809031</StyleId>
                <LayoutLayers>4</LayoutLayers>
                <BlockScale/>
                <JobItemIds>
                    <JobItemId>9083675</JobItemId>
                    <JobItemId>9088148</JobItemId>
                </JobItemIds>
            </Block>
            <Block MapFieldMask="true" CompressText="false" CombineRaster="false">
                <Name>hel</Name>
                <StyleId>24809032</StyleId>
                <LayoutLayers>-</LayoutLayers>
                <BlockScale/>
                <JobItemIds>
                    <JobItemId>9022173</JobItemId>
                    <JobItemId>25403646</JobItemId>
                </JobItemIds>
            </Block><Block MapFieldMask="true" CompressText="false" CombineRaster="false">
                <Name>shade glacier</Name>
                <StyleId>24809041</StyleId>
                <LayoutLayers>-</LayoutLayers>
                <BlockScale/>
                <JobItemIds>
                    <JobItemId>24806040</JobItemId>
                </JobItemIds>
            </Block>
            <Block MapFieldMask="true" CompressText="false" CombineRaster="false">
                <Name>shade</Name>
                <StyleId>24809040</StyleId>
                <LayoutLayers>-</LayoutLayers>
                <BlockScale/>
                <JobItemIds>
                    <JobItemId>24806038</JobItemId>
                </JobItemIds>
            </Block>
        </Blocks>
        <Offset X="0" Y="0"/>
        <Name>DS</Name>
    </Frame></MapSheet>

这个简单的 SELECT 获取数据不起作用:

SELECT x.MapSheet
FROM XmlTable('/MapSheet') PASSING XmlType(MAPSHEET.STRUCTURE,1)
    COLUMS "XML" VARCHAR2(300) PATH 'MapSheet') AS x;

如何从 blob 列中选择/更新所需的 xml 数据?

【问题讨论】:

    标签: xml oracle blob


    【解决方案1】:

    要从 XML 中进行选择,您可以使用 ExtractValue(XmlType, XPath)XmlTable 将 Xml clob 转换为可查询的 XML 表。对于 BLOB 转换,你应该可以只用XmlType(blob_value, 1) 包装它,然后你可以对其执行任何与 XML 相关的功能。

    SELECT ExtractValue(
              XmlType('<test><node1>value1</node1><node2>value2</node2></test>'), 
                      '/test/node1') as Node1 
    FROM dual;
    

    或使用XmlTable

    SELECT xt.Node1, xt.Node2
    FROM XmlTable('/test/block'
             PASSING XmlType('<test>
    <block><node1>value1a</node1><node2>value2a</node2></block>
    <block><node1>value1b</node1><node2>value2b</node2></block>
    <block><node1>value1c</node1><node2>value2c</node2></block>
    </test>')
            COLUMNS
            "Node1"     VARCHAR2(20)   PATH 'node1',
            "Node2"     VARCHAR2(20)   PATH 'node2') AS xt;
    

    使用 UpdateXml,假设我正在更新的记录在一列中有上述 XML:

    UPDATE MyTable SET xml_data =
    UpdateXml(xml_data, '/test/block/node2[text() = "value2b"]/text()', 'value2z')
    WHERE data_id = 1;
    

    以上内容应将具有值value2bnode2 更新为现在具有value2z。然后返回新的 XML 并将其分配给记录中与 data_id = 1 匹配的列 xml_data

    请注意,在上面的查询中,它正在处理一个已经是 XmlType 类型的列。您正在使用BLOB。我会问,它是BLOB 而不是CLOBXmlType 有什么原因吗?如果您要存储 VARCHAR 类型的数据,您应该使用后两种类型中的一种,CLOB 如果您要存储各种 VARCHAR 数据,以及 XmlType(无论如何,这是一种更具体的 CLOB ) 如果您严格存储 XML 数据。

    如果您无法使用BLOB 数据类型,您将需要执行大量转换。使用XmlType(blob_data, 1) 应该可以让您从BLOBXmlType,但是返回您可能需要使用UTL_RAW.CAST_TO_RAW(xml_data)。所以查询会变成:

    UPDATE MyTable SET clob_data =
    UTL_RAW.CAST_TO_RAW(
        UpdateXml(XmlType(clob_data, 1), '/test/block/node2[text() = "value2b"]/text()', 'value2z').GetClobVal()
    )
    WHERE data_id = 1;
    

    这是一个独立的示例,展示了上述各种方法:

    DECLARE varchar_data    VARCHAR2(500);
            blob_data       BLOB;
            xml_data        XMLType;
            node1Val        VARCHAR(20);
            node2Val        VARCHAR(20);
    
    BEGIN
        select '<test>
    <group><node1>value1a</node1><node2>value2a</node2></group>
    <group><node1>value1b</node1><node2>value2b</node2></group>
    <group><node1>value1c</node1><node2>value2c</node2></group>
    <group><node1>value1d</node1><node2>value2d</node2></group>
    </test>' into varchar_data from dual;
    
        select UTL_RAW.CAST_TO_RAW(varchar_data) into blob_data from dual;
    
        select XmlType(blob_data, 1) into xml_data from dual;
        dbms_output.put_line(xml_data.getClobVal());
    
        select xt.Node1, xt.Node2
        into node1Val, node2Val
        from XmlTable('/test/group' 
            passing XmlType(blob_data, 1)
            columns Node1     VARCHAR2(20)    path 'node1',
                    Node2     VARCHAR2(20)    path 'node2'
            ) xt
        where xt.Node1 = 'value1c';
        dbms_output.put_line('node1Val = ''' || node1Val || ''', node2Val = ''' || node2Val || ''';'); 
    
        -- Using UpdateXml to update the XML, that will return an XmlType 
        -- so we call GetClobVal() to let CAST_TO_RAW convert to BLOB.
        select UTL_RAW.CAST_TO_RAW(
            UpdateXml(
                XmlType(blob_data, 1), 
                '/test/group/node2[../node1/text() = "value1c"]/text()', 
                'zzzz').GetClobVal()
            ) into blob_data
        from dual; 
    
        select XmlType(blob_data, 1) into xml_data from dual;
        dbms_output.put_line(xml_data.getClobVal());
    
        select xt.Node1, xt.Node2
        into node1Val, node2Val
        from XmlTable('/test/group' 
            passing XmlType(blob_data, 1)
            columns Node1     VARCHAR2(20)    path 'node1',
                    Node2     VARCHAR2(20)    path 'node2'
            ) xt
        where xt.Node1 = 'value1c';
        dbms_output.put_line('node1Val = ''' || node1Val || ''', node2Val = ''' || node2Val || ''';'); 
    
    END;
    

    【讨论】:

    • 嗨,我不能再使用 ExtractValue 命令,因为它已被弃用。因此,我必须在您的示例中使用 XmlTable 进行尝试。但是缺少 blob 到 clob 的转换,更新语句也是如此,简单的环绕 XMLType(blob_value) 方法不起作用。您能否为其添加完整的语法。会很棒!
    • @happymapper - 抱歉忘记在 XmlType 函数中包含指示字符集 (1 = USASCII) 的参数。
    • 您的选择示例仍然无法正常工作,因为 XMLType 语法仍在使用 XML 数据。我们的表中使用了 blob,因为这是我们系统的默认设置,我不应该更改它。
    • XmlType 仍在使用 XML 数据是什么意思?我将用一个独立的示例更新我的答案。
    • 我的意思是您传递的 XmlType(....) 语句使用纯 XML 数据而不是所需的 blob 数据类型。您的独立示例非常完美。非常感谢您的支持和建议,非常感谢。
    【解决方案2】:
    create table testxmlBlob (p blob);
    

    在表格中插入一些 xml 文档。

    insert into  testxmlBlob values( utl_raw.cast_to_raw('<?xml version="1.0"?>
    <catalog>
       <book id="bk101">
          <author>Gambardella, Matthew</author>
          <title>XML Developer''s Guide</title>
          <genre>Computer</genre>
          <price>44.95</price>
          <publish_date>2000-10-01</publish_date>
          <description>An in-depth look at creating applications 
          with XML.</description>
       </book>
       <book id="bk102">
          <author>Ralls, Kim</author>
          <title>Midnight Rain</title>
          <genre>Fantasy</genre>
          <price>5.95</price>
          <publish_date>2000-12-16</publish_date>
          <description>A former architect battles corporate zombies, 
          an evil sorceress, and her own childhood to become queen 
          of the world.</description>
       </book></catalog>')) ;
    

    查看插入的 xml。 xmltype(blob,csid -charset enocoding id '0' is default)

    select xmlserialize(document xmltype(p,0)) from  testxmlBlob;  
    

    使用 xmlquery 将 &lt;description&gt; 更改为 &lt;descriptionNew&gt;。 它也可以用于更新语句update testxmlBlob set p = XMLQuery(....) ...

     select XMLQuery('copy $i := $p1
                  modify
                  (
                 for $j in $i/catalog/book/description
                 let $newn := <descriptionNew>newDescription</descriptionNew>
                 return replace node $j with $newn)
                 return $i             
                 ' PASSING xmltype(p,0) AS "p1"     
              RETURNING CONTENT) readable
              ,xmlserialize(document XMLQuery('copy $i := $p1
                  modify
                  (
                 for $j in $i/catalog/book/description
                 let $newn := <descriptionNew>newDescription</descriptionNew>
                 return replace node $j with $newn)
                 return $i             
                 ' PASSING xmltype(p,0) AS "p1" 
              RETURNING CONTENT) as BLOB) blob_value
              from  testxmlBlob;  
    

    Other example how to use xmlquery to update

    【讨论】:

    • 非常感谢!!现在一切都好!
    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 2013-06-07
    • 2018-10-05
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多