查询包含XML消息的CLOB列

时间:2014-10-07 14:34:31

标签: sql xml oracle plsql clob

我试图对表格进行数据处理。该表包含使用CLOB数据类型存储xml消息的列。 XML消息具有以下结构:

<t:MsgNameXML typeInfo="source" xsi:schemaLocation="http://example/location FileName.xsd" xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"      >
    <t:info1>data1</t:info1>
    <t:info2>data2</t:info2>
    <t:Section>
        <t:SubSection>
            <t:SubSubSection>
                <t:variable1>data3</t:variable1>
                <t:variable2>data4</t:variable2>
            </t:SubSubSection>
        </t:SubSection>
    </t:Section>
    <t:Section>
        <t:SubSection>
            <t:SubSubSection>
                <t:variable1>data5</t:variable1>
                <t:variable2>data6</t:variable2>
            </t:SubSubSection>
        </t:SubSection>
    </t:Section>
</t:MsgNameXML>

所以,至少对我来说,主要的困难是命名空间和存在多个节点的事实。

我希望得到以下输出(对于包含上述XML的记录):

INFO1   INFO2   VARIABLE1   VARIABLE2
-------------------------------------
data1   data2   data3       data4
data1   data2   data5       data6

我构建了以下查询以尝试提取&#34; variable1&#34; (Oracle数据库,所以PL SQL,我猜):

select 
extractvalue(xmltype(CLOB_COLUMN_NAME),
'/t:MsgNameXML/t:Section/t:SubSection/t:SubSubSection/t:variable1',
'xmlns:t="xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')

from 
TABLE_NAME,
TABLE(XMLSEQUENCE(EXTRACT(CLOB_COLUMN_NAME, '/t:MsgNameXML/t:Section/t:SubSection/t:SubSubSection/t:variable1')))

遗憾的是,这会产生以下错误消息:

ORA-00932: inconsistent datatypes: expected - got -
00932. 00000 -  "inconsistent datatypes: expected %s got %s"
*Cause:    
*Action:
Error at Line: 9 Column: 33

(第9行,第33列,指的是CLOB_COLUMN_NAME位于from子句中的EXTRACT函数之后的位置。)

有谁知道我做错了什么,我怎么能纠正这个?

此外,我需要扩展此查询以从XML消息中提取更多值,而不仅仅是&#34; variable1&#34; (见上面所需的结果)。对此的任何帮助也将非常感激。

感谢您的帮助,

汤姆

1 个答案:

答案 0 :(得分:1)

您的ORA-00932的直接原因是您试图直接从CLOB中提取;你已经在一个地方转换了,但是这个:

TABLE(XMLSEQUENCE(EXTRACT(CLOB_COLUMN_NAME, ... )))

......需要:

TABLE(XMLSEQUENCE(EXTRACT(XMLType(CLOB_COLUMN_NAME), ... )))

但是该命名空间仍然没有得到认可,如果您只改变它,那么您将获得ORA-31011。您可以通过在EXTRACT调用中包含命名空间来解决问题,并纠正错误:

select extractvalue(column_value, '/t:variable1',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as variable1
from 
TABLE_NAME,
TABLE(XMLSEQUENCE(EXTRACT(XMLType(CLOB_COLUMN_NAME),
  '/t:MsgNameXML/t:Section/t:SubSection/t:SubSubSection/t:variable1',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')));

VARIABLE1
----------
data3      
data5      

或者通过将提取物移回一个级别来同时显示两个变量:

select extractvalue(column_value, 't:SubSubSection/t:variable1',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as variable1,
  extractvalue(column_value, 't:SubSubSection/t:variable2',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as variable2
from 
TABLE_NAME,
TABLE(XMLSEQUENCE(EXTRACT(XMLType(CLOB_COLUMN_NAME),
  '/t:MsgNameXML/t:Section/t:SubSection/t:SubSubSection',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')));

VARIABLE1  VARIABLE2
---------- ----------
data3      data4      
data5      data6      

包括信息值也会使其变得更加复杂和重复:

select extractvalue(XMLType(CLOB_COLUMN_NAME), 't:MsgNameXML/t:info1',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as info1,
  extractvalue(XMLType(CLOB_COLUMN_NAME), 't:MsgNameXML/t:info2',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as info2,
  extractvalue(column_value, 't:SubSubSection/t:variable1',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as variable1,
  extractvalue(column_value, 't:SubSubSection/t:variable2',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')
  as variable2
from 
TABLE_NAME,
TABLE(XMLSEQUENCE(EXTRACT(XMLType(CLOB_COLUMN_NAME),
  '/t:MsgNameXML/t:Section/t:SubSection/t:SubSubSection',
  'xmlns:t="http://url/of/custom/namespace" xmlns:"http://url/of/default/namespace"')));

INFO1      INFO2      VARIABLE1  VARIABLE2
---------- ---------- ---------- ----------
data1      data2      data3      data4      
data1      data2      data5      data6      

SQL Fiddle这种方法。


您可以使用XQuery and XMLTable代替旧的提取语法:

select info1, info2, variable1, variable2
from table_name,
  xmltable('declare namespace t = "http://url/of/custom/namespace"; (: :)
    for $i in /t:MsgNameXML
      let $info1 := $i/t:info1,
        $info2 := $i/t:info2
      for $j in $i/t:Section/t:SubSection/t:SubSubSection
        let $variable1 := $j/t:variable1,
          $variable2 := $j/t:variable2
      return <tmp>
          <info1>{$info1}</info1>
          <info2>{$info2}</info2>
          <variable1>{$variable1}</variable1>
          <variable2>{$variable2}</variable2>
        </tmp>'
passing xmltype(CLOB_COLUMN_NAME)
columns
  info1     char(10) path '/tmp/info1',
  info2     char(10) path '/tmp/info2',
  variable1 char(10) path '/tmp/variable1',
  variable2 char(10) path '/tmp/variable2'
);

INFO1      INFO2      VARIABLE1  VARIABLE2
---------- ---------- ---------- ----------
data1      data2      data3      data4      
data1      data2      data5      data6      

SQL Fiddle

我必须稍微调整CLOB值以使其有效;将xsi=更改为xmlns:xsi=并为默认命名空间xmlns:x="http://url/of/default/namespace"设置虚拟名称。我想那都是......

XQuery是一种基于序列&#34;的功能语言,它使用"FLOWR" expressions。特别是两个for循环遍历结构,let表达式将命名空间变量分配给局部变量,然后以更简单的XML结构返回,从中可以通过新路径提取列。 (您似乎无法直接在path字符串中使用名称空间。)

扩展此功能可以非常轻松地从您的消息中获取更多价值 - 更多let个表达式和更多匹配的path提取。

但我自己真的只是抓住这些东西的表面,所以可能有更简单/更好/更快的方法来做到这一点;无论如何,希望是XQuery方法的起点。