从Oracle XMLType中粉碎数据

时间:2015-01-30 22:25:48

标签: oracle xpath

我一直把头发拉过来(剩下的就是这样),并且想知道你是否在Oracle的XPath逻辑中看到了我没有看到的东西。我通过Oracle的文档研究了各种函数和XPath方法无济于事。

在下面的示例中,表pg_xml_stg包含属性pressganey_xml(XMLType)。以下内容示例:

<PATIENTLEVELDATA>
                <SURVEY_ID>826434950</SURVEY_ID>
                <CLIENT_ID>7145</CLIENT_ID>
                <SERVICE>IN</SERVICE>
                <RECDATE>2014-11-26</RECDATE>
                <DISDATE>2014-07-04</DISDATE>
                <ANALYSIS>
                     <RESPONSE>
                             <VARNAME>A1</VARNAME>
                             <VALUE>5</VALUE>

这是一个将数据下拉到响应级别的查询,但不包括来自患者级别(survey_id)的数据。不确定我的XPATH字符串是否已关闭或实际的xmlsequence调用是否实际上不会将数据拉到ANALYSIS上面。

SELECT    extractvalue (Value (pg), '//VARNAME/text()') as PG_VARNAME
         ,extractvalue (Value (pg), '//VALUE/text()') as PG_VARNAME
         ,extractvalue (Value (pg), '../../SURVEY_ID/text()') as PG_VARNAME
FROM v500.pg_xml_stg
    ,TABLE (xmlsequence (extract (pressganey_xml, '//PATIENTLEVELDATA/ANALYSIS/RESPONSE'))) pg

PG_VARNAME  PG_VARNAME  PG_VARNAME
A1                           5              
A2                           5              
D1                           5              
D2                           5              
D3                           5              
I1                           5              
I17                          5              
I6                           5    

我可以通过索引VARRAY来获得下面的查询,但它不允许超出1级的任何内容。

SELECT extractvalue (Value (pg), '//PATIENTLEVELDATA/SURVEY_ID/text()') as PG_SURVEY_ID
,extractvalue (Value (pg), '//PATIENTLEVELDATA/ANALYSIS[1]/RESPONSE[1]/VARNAME[1]/text()') as PG_VARNAME
,extractvalue (Value (pg), '//PATIENTLEVELDATA/ANALYSIS[1]/RESPONSE[1]/VALUE[1]/text()') as PG_VALUE
FROM v500.pg_xml_stg
, TABLE (xmlsequence (extract (pressganey_xml, '*/PATIENTLEVELDATA'))) pg

PG_SURVEY_ID                 PG_VARNAME  PG_VALUE
826434950                           A1                           5
830145105                           A1                           5
842152499                           A1                           4
846003814                           A1                           5
850619251                           D1                           3
850711623                           A1                           4
851482310                           A1                           5

谢谢,

布赖恩

1 个答案:

答案 0 :(得分:0)

在您的第一个查询中,调查ID不可用,因为pg仅包含回复;原始XML中的数据不能用于extractvalue()次调用,因为它没有通过。你正在做的是类似于将值的substr传递给函数并期望函数知道整个原始字符串。

在第二个查询中,您只需指定每个节点名称的第一个实例,如您所知。并且因为每个级别都有多个节点,所以无论如何都不能使用extractvalue(),尝试获取多个节点会抛出ORA-19025: EXTRACTVALUE returns value of only one node。而且extractvalue() is deprecated无论如何。

要获取多个值,您可以使用the XMLTable() function将XML层次结构转换为更像关系数据的内容。

您的XML代码段不会显示整个结构或节点如何重复,但是从您的查询及其结果向后工作,这样的事情可能足够接近以获得一般性的想法:

<?xml version="1.0"?>
<DATA>
  <PATIENTLEVELDATA>
  <SURVEY_ID>826434950</SURVEY_ID>
  <CLIENT_ID>7145</CLIENT_ID>
  <SERVICE>IN</SERVICE>
  <RECDATE>2014-11-26</RECDATE>
  <DISDATE>2014-07-04</DISDATE>
    <ANALYSIS>
      <RESPONSE>
        <VARNAME>A1</VARNAME>
        <VALUE>5</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>A2</VARNAME>
        <VALUE>6</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>D1</VARNAME>
        <VALUE>7</VALUE>
      </RESPONSE>
    </ANALYSIS>
    <ANALYSIS>
      <RESPONSE>
        <VARNAME>A1</VARNAME>
        <VALUE>8</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>A2</VARNAME>
        <VALUE>9</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>D1</VARNAME>
        <VALUE>10</VALUE>
      </RESPONSE>
    </ANALYSIS>
  </PATIENTLEVELDATA>
  <PATIENTLEVELDATA>
  <SURVEY_ID>830145105</SURVEY_ID>
  <CLIENT_ID>7146</CLIENT_ID>
  <SERVICE>IN</SERVICE>
  <RECDATE>2014-11-27</RECDATE>
  <DISDATE>2014-07-04</DISDATE>
    <ANALYSIS>
      <RESPONSE>
        <VARNAME>A1</VARNAME>
        <VALUE>3</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>A2</VARNAME>
        <VALUE>4</VALUE>
      </RESPONSE>
      <RESPONSE>
        <VARNAME>D1</VARNAME>
        <VALUE>7</VALUE>
      </RESPONSE>
    </ANALYSIS>
    <ANALYSIS>
      <RESPONSE>
        <VARNAME>A1</VARNAME>
        <VALUE>11</VALUE>
      </RESPONSE>
    </ANALYSIS>
  </PATIENTLEVELDATA>
</DATA>

然后是这样的查询:

select x.*
from pg_xml_stg pxs
cross join xmltable('for $i in //PATIENTLEVELDATA, $j in $i/ANALYSIS/RESPONSE
  return <tmp
      pg_survey_id="{$i/SURVEY_ID}"
      pg_varname="{$j/VARNAME}"
      pg_value="{$j/VALUE}"
    />'
  passing pxs.pressganey_xml
  columns
      pg_survey_id number path '/tmp/@pg_survey_id',
      pg_varname varchar2(10) path '/tmp/@pg_varname',
      pg_value number path '/tmp/@pg_value'
) x;

获取输出:

PG_SURVEY_ID PG_VARNAME   PG_VALUE
------------ ---------- ----------
   826434950 A1                  5 
   826434950 A2                  6 
   826434950 D1                  7 
   826434950 A1                  8 
   826434950 A2                  9 
   826434950 D1                 10 
   830145105 A1                  3 
   830145105 A2                  4 
   830145105 D1                  7 
   830145105 A1                 11 

 10 rows selected 

它的所有响应VARNAME / VALUE与其父节点相对应&#39; SURVEY_ID

XPath使用$i来获取PATIENTLEVEL节点,然后在$j内获取与每个节点相关的RESPONSE节点,从而展平数据。您感兴趣的值将合并为tmp子句中虚拟return节点的属性;为每个响应生成类似的内容:

<tmp pg_survey_id="826434950" pg_varname="A1" pg_value="5" />

passing子句刚刚从表中标识了XMLType列,并将其传递给XPath。并且columns子句将虚拟tmp节点中的属性转换为关系列。

我猜测调查ID和响应值都是数字,但您可以调整所有这些数据类型以匹配您真正拥有的数据类型。