0

首先,我的桌子看起来像这样..

Checkpoint_Data
---------------
Checkpoint_Id
Sequence_Number
Checkpoint_Data

Checkpoint
----------
Checkpoint_Id
Location
Transaction_Id

Transaction
-----------
Transaction_Id
Name
Time

Checkpoint_data 包含分解的 XML,序列号决定了它如何组合在一起

我想将所有 Checkpoint 的链接 Checkpoint_Data 按顺序 (1,2,..) 连接在一起,然后使用 XPath 提取一些我想要的数据。

这是我现在的查询,但它没有进行任何连接,并且无法正常工作:

SELECT distinct(xmltype(data.trans_data).extract('//somePath/text()').getStringVal())  
FROM Checkpoint_Data cpd, Checkpoint cp, Transaction tr
WHERE cpd.checkpoint_id = cp.checkpoint_id
     and cp.location = 'someLocation'
     and cp.trans_id = tr.trans_id
     and tr.time >= to_date('3/26/2013:8:00 AM', 'mm/dd/yyyy:hh:miam')  
     and tr.time <= to_date('3/26/2013:11:00 AM', 'mm/dd/yyyy:hh:miam') 

如何连接 Checkpoint_Data 中包含的分解 XML,然后使用 XPath 从中提取数据?

4

1 回答 1

1

PLSQL 方法:

SQL> create or replace function get_xml_doc(p_id Checkpoint_Data.checkpoint_id%type)
  2    return xmltype deterministic
  3  is
  4    v_xml clob;
  5  begin
  6    for r_row in (select cd.checkpoint_data
  7                    from Checkpoint_Data cd
  8                   where cd.checkpoint_id = p_id
  9                   order by cd.sequence_number)
 10    loop
 11      v_xml := v_xml || r_row.checkpoint_data;
 12    end loop;
 13
 14    return xmltype(v_xml);
 15  end get_xml_doc;
 16  /

Function created.

SQL>
SQL> select cp.checkpoint_id, get_xml_doc(cp.checkpoint_id) xml_doc
  2    from checkpoint cp, transaction tr
  3   where cp.location = 'someLocation'
  4     and cp.trans_id = tr.trans_id
  5     and tr.time <= sysdate
  6   group by cp.checkpoint_id;

CHECKPOINT_ID XML_DOC
------------- ----------------------------------------
            1 <root>
                <a>1st node</a>
                <b>2nd node</b>
                <compType>
                  <a>foo</a>
                </compType>
                <d>another node</d>
              </root>

或者如果 PLSQL 不是一个选项,则只是 SQL:

您可以使用CDATA例如XMLAGG

SQL> select * from Checkpoint_Data;

CHECKPOINT_ID SEQUENCE_NUMBER CHECKPOINT_DATA
------------- --------------- --------------------------------------------------
            1               1 <root><a>1st node</a><b>2nd node</b>
            1               2 <compType><a>foo</a></compType><d>another node</d>
            1               3 </root>


SQL> select c.xmlstr.transform(xmltype('<xsl:stylesheet version="1.0"
  2          xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3          <xsl:output method="xml" omit-xml-declaration = "yes" version="1.0" />
  4          <xsl:template match="/">
  5              <xsl:for-each select="/root/nde">
  6                  <xsl:sort select="@seq"/>
  7                  <xsl:value-of select="." disable-output-escaping="yes" />
  8              </xsl:for-each>
  9          </xsl:template>
 10      </xsl:stylesheet>')) xml
 11    from (SELECT cpd.checkpoint_id,xmlelement("root", xmlagg(
 12                 xmltype('<nde seq="' || cpd.sequence_number || '"><![CDATA['||cpd.checkpoint_data||']]></nde>'))) xmlstr
 13          FROM Checkpoint_Data cpd, Checkpoint cp, Transaction tr
 14          WHERE cpd.checkpoint_id = cp.checkpoint_id
 15               and cp.location = 'someLocation'
 16               and cp.trans_id = tr.trans_id
 17               and tr.time <= sysdate
 18           group by cpd.checkpoint_id) c;

XML
--------------------------------------------------------------------------------
<root><a>1st node</a><b>2nd node</b><compType><a>foo</a></compType><d>another no
de</d></root>

所以我把每个 xml 片段转换成一个 CDATA 节点,比如:

<node seq="1"><!CDATA[<root><a>1st node</a><b>2nd node</b>]]></node>

然后用来XMLAGG将它们放入一个文档中,例如

<root>
  <node seq="1"><!CDATA[<root><a>1st node</a><b>2nd node</b>]]></node>
  <node seq="3"><!CDATA[</root>]]></node>
  <node seq="2"><!CDATA[<compType><a>foo</a></compType><d>another node</d>]]></node>
</root>

注意:这些序列可能会被 group by.. 混杂在一起,所以我应用了 XSL 对它们进行排序并打印它们(如果需要,您可以编写自己的聚合来按顺序执行此操作,或者只是编写一个pl/sql例程来获取所有片段和按顺序为您附加它们,如果这是一个选项,您可能更喜欢)。

注意:在 10g 中,oracle 似乎忽略了禁用输出转义(在 11g 中可以)。如果你使用 10g,你可以添加一个调用dbms_xmlgen.convert(clob, 1)来解码它。

select dbms_xmlgen.convert(
         xmlserialize(
           content c.xmlstr.transform(xmltype('<?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" version="1.0" omit-xml-declaration = "yes"  encoding="UTF-8" indent="no"/>
        <xsl:template match="/">
            <xsl:for-each select="/root/node">
                <xsl:sort select="@seq"/>
                <xsl:value-of select="." disable-output-escaping="yes"/>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>')) as clob), 1) xsl, xmlstr
  from (SELECT cpd.checkpoint_id,xmlelement("root", xmlagg(
               xmltype('<node seq="' || cpd.sequence_number || '"><![CDATA['||cpd.checkpoint_data||']]></node>'))) xmlstr
        FROM Checkpoint_Data cpd, Checkpoint cp, Transaction tr
        WHERE cpd.checkpoint_id = cp.checkpoint_id
             and cp.location = 'someLocation'
             and cp.trans_id = tr.trans_id
             and tr.time <= sysdate
         group by cpd.checkpoint_id) c;

小提琴:http ://sqlfiddle.com/#!4/e1bf8/1

于 2013-03-26T17:56:27.770 回答