使用XMLQUERY选择并更新Oracle BLOB列

时间:2016-01-14 10:06:47

标签: xml oracle blob

我必须更新存储在Oracle 11G中BLOB列中的XML值。 BLOB存储了一个comlete 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数据?

2 个答案:

答案 0 :(得分:0)

要从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;

以上内容应该更新node2,其价值为value2b,而现在更新为value2z。然后返回新XML并将其分配给匹配xml_data的记录中的列data_id = 1

注意,在上面的查询中,它使用的是一个已经是XmlType类型的列。您正在使用BLOB。我会问,是否有BLOB代替CLOBXmlType的原因?如果您要存储VARCHAR类型数据,那么您应该使用后两种类型中的一种,CLOB如果要存储各种VARCHAR数据,XmlType(这是如果要存储严格的XML数据,则更具体的CLOB类型。

如果您使用BLOB数据类型,则需要执行大量转换。使用XmlType(blob_data, 1)可以让您从BLOB转到XmlType,但回过头来看,您可能需要使用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;

答案 1 :(得分:0)

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将<description>更改为<descriptionNew>。 它也可以在更新语句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