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