SQL XML список узлов, разделенных запятой
У меня есть нормальная таблица SQL, один из столбцов XML, пример:
...
<Element><id>first</id></Element>
<Element><id>second</id></Element>
...
Мне нужно получить список идентификаторов, разделенных запятыми:
id_list
---
first,second
На данный момент я добился этого, создав XMLTABLE с идентификаторами:
id
----
first
second
а затем с помощью функции LISTAGG Oracle. Интересно, существует ли какая-нибудь функция / цикл (возможно, FLWOR?), Чтобы получить тот же результат, но не преобразовывать входные данные XML в XMLTABLE.
Большое спасибо за помощь
2 ответа
Вы можете сделать это с помощью функции XMLDB, используя XPath. string-join
функция
Как XMLQuery, если у вас есть одно значение для обработки (с вашими примерами данных, предоставленными через CTE и фиктивный корневой узел):
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
Или с 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
Я не уверен, что есть много преимуществ в этом listagg()
, но может быть интересно сравнить производительность обоих с вашими реальными данными, особенно если есть много узлов. За исключением того, что, изменив тип столбца XMLTable на CLOB, вы можете получить большее значение из той версии, которое вы можете использовать с listagg()
,
Если вы должны, вы можете сделать что-то вроде того, что я показываю в запросе ниже.
Однако я не считаю это хорошим подходом; что вы делаете в настоящее время, создав таблицу XML и затем используя LISTAGG
кажется лучше.
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