简体   繁体   中英

SQL XML list of nodes separated by comma

I have a normal SQL table, one of the column is an XML, example:

...
<Element><id>first</id></Element>
<Element><id>second</id></Element>
...

I need to get the list of id's separated by commas:

id_list
---
first,second

For now, I have achieved it creating an XMLTABLE with the ids:

id
----
first
second

and then using the LISTAGG function of Oracle. I wonder if exist some function/loop (maybe FLWOR?) to get the same result but not converting the XML input to an XMLTABLE.

Thanks a lot for helping

If you must, you could do something like what I show in the query below.

However, I don't view this as a good approach; what you are doing currently, by creating an XML table and then using LISTAGG , seems better.

with inputs ( xml_str ) as (
       select '...
               <Element><id>first</id></Element>
               <Element><id>second</id></Element>
               ...'
       from dual
     )
-- End of test data (not part of the solution); SQL query begins below this line
select rtrim( regexp_replace( xml_str, '.*?(<Element><id>(.*?)</id></Element>|$)'
                            , '\2,', 1, 0, 'n')
            , ',') as id_list
from   inputs
;



ID_LIST
------------
first,second

You could so it just within the XMLDB function, with XPath string-join function .

As an XMLQuery if you have a single value to process (with your sample data provided via a CTE and a dummy root node):

with t (xml) as (
  select xmltype('<root>
<Element><id>first</id></Element>
<Element><id>second</id></Element>
</root>') from dual
)
select xmlquery('
  for $i in /root
    return <e>{ fn:string-join($i/Element/id, ",") }</e>/text()'
  passing xml
  returning content
) as result
from t;

RESULT                                                                          
--------------------------------------------------------------------------------
first,second

Or with an XMLTable:

with t (xml) as (
  select xmltype('<root>
<Element><id>first</id></Element>
<Element><id>second</id></Element>
</root>') from dual
)
select x.*
from t
cross join xmltable('
  for $i in /root
    return <e>{ fn:string-join($i/Element/id, ",") }</e>'
  passing xml
  columns result varchar2(4000) path '.'
) x;

RESULT                                                                          
--------------------------------------------------------------------------------
first,second

I'm not sure there's much advantage in doing that over listagg() , but might be interesting to compare the performance of both with your real data, particularly if there are a lot of nodes. Except, by changing the XMLTable column type to CLOB, you can get a larger value out of that version that you can with listagg() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM