| Oracle FAQ | Your Portal to the Oracle Knowledge Grid | |
|  |  | |||
Home -> Community -> Usenet -> c.d.o.misc -> Re: Querying XMLType data (CLOB storage)
Ralph Weires wrote:
<snip>
> Assume i stored the following two example documents in two rows of the
> table:
> 
> ROW 1:
>   ID: 1
>   DATA: <document>
>           <person>
>             <name>Someone</name>
>           </person>
>         </document>
> 
> ROW 2:
>   ID: 2
>   DATA: <document>
>           <person>
>             <name>Anyone</name>
>           <person>
>           <person>
>             <name>Someone else</name>
>           </person>
>         </document>
<snip>
> The result i'd like to get i something like
> 
>   NAMES
>   -------------------
>   Someone
>   Anyone
>   Someone else
> 
> with the different matching entries of a *single* row being separated in
> multiple rows of the returned result set.
<snip>
I don't believe there is a way to pivot a row into multiple rows using the basic XDB interfaces. Here's a pipeline table function I wrote that will split a cursor of XMLTYPE documents into a separate XMLTYPE document for each child element of each document (note: I didn't test this very thoroughly).
create or replace type ttab_xmltype is table of xmltype /
create or replace function xmltype_split(
     in_refcur sys_refcursor)
     return ttab_xmltype pipelined is
     xml xmltype;
     doc dbms_xmldom.domdocument;
     root_element dbms_xmldom.domelement;
     root_node dbms_xmldom.domnode;
     child_node dbms_xmldom.domnode;
     child_clob clob;
     child_xml xmltype;
begin
dbms_lob.createtemporary(child_clob, cache => true);
loop
         fetch in_refcur into xml;
         exit when in_refcur%notfound;
         -- get a dom for the xmltype so we can
         -- navigate through it.
         doc := dbms_xmldom.newdomdocument(xml);
         root_element := dbms_xmldom.getdocumentelement(doc);
         root_node := dbms_xmldom.makenode(root_element);
         -- now walk through each child and pivot
         -- that out as a separate xmltype
         child_node := dbms_xmldom.getfirstchild(root_node);
         loop
             exit when dbms_xmldom.isnull(child_node);
             -- convert the child node to an xmltype
             dbms_xmldom.writetoclob(child_node, child_clob);
             child_xml := xmltype(child_clob);
             -- pipe the child node out as it's own
             -- xmltype on it's own row
             pipe row(child_xml);
             child_node := dbms_xmldom.getnextsibling(child_node);
         end loop;
         dbms_xmldom.freedocument(doc);
     end loop;
     return;
end;
/
Then you could do something like ...
select *
from table(xmltype_split(cursor(
     select sys_xmlagg(x.data.extract('/document/person/name')) name
     from xmltable x
     )))
<name>Someone</name> <name>Anyone</name> <name>Someone else</name>
3 rows selected.
Which, of course, would also allow ...
select x.column_value.extract('/name/text()') name from table(xmltype_split(cursor(
     select sys_xmlagg(x.data.extract('/document/person/name')) name
     from xmltable x
     ))) x
NAME
3 rows selected.
I'd be interested to see if someone has a simpler solution (other than hard coded parsing and self joins, etc...).
Richard Kuhler Received on Wed Sep 03 2003 - 18:12:09 CDT
|  |  |